2011-06-24 30 views
7

Tôi có một vấn đề thú vị khi một lớp kế thừa từ một lớp thực hiện IEnumerable, nhưng tôi cũng muốn lớp thực hiện IEnumerable cho một kiểu khác. Mọi thứ hoạt động ngoại trừ các phương thức mở rộng của IEnumerable, có nghĩa là tôi không thể thực hiện bất kỳ LINQ nào với các đối tượng theo mặc định mà không phải luôn luôn truyền trước. Có ai có bất kỳ ý tưởng ngoài việc liên tục đúc?Tại sao tôi không thể sử dụng LINQ to Objects khi lớp của tôi triển khai IEnumerable <T> nhiều lần?

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace LinqTesting 
{ 
    public class Trucks<T> : Vehicles, IEnumerable<Truck> 
    {  
     public Trucks() 
     {  
      // Does Compile 
      var a = ((IEnumerable<Truck>)this).FirstOrDefault(); 
      // Doesn't Compile, Linq.FirstOrDefault not found 
      var b = this.FirstOrDefault(); 
     }  

     public new IEnumerator<Truck> GetEnumerator() { throw new NotImplementedException(); } 
    }  

    public class Vehicles : IEnumerable<Vehicle> 
    {  
     public IEnumerator<Vehicle> GetEnumerator() { throw new NotImplementedException(); } 
     System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw new NotImplementedException(); } 
    }  

    public class Vehicle { } 

    public class Truck : Vehicle { } 
}  
+2

Đối tượng xe tải của bạn có kế thừa hai loại IEnumerable không? Làm thế nào để bạn mong đợi trình biên dịch để tìm ra loại enumerable bạn muốn sử dụng, hãy thử upcasting vào một trong những bạn muốn và sau đó chọn FirstOrDefault –

Trả lời

6

Trên thực tế bạn có thể, nhưng bạn không thể tận dụng lợi thế của chung loại suy luận, bởi vì lớp học của bạn thực hiện hai IEnumerable<T> của hai loại khác nhau và trình biên dịch không thể biết loại bạn muốn sử dụng.

Bạn có thể xác định nó direclty, như:

var b = this.FirstOrDefault<Truck>(); 
+0

Đây thực sự là những gì tôi đã bỏ lỡ. Nó đã gây nhầm lẫn vì intellisense sẽ bật lên hiển thị phương pháp, nhưng nó cũng sẽ hiển thị lỗi trong cùng một dòng bởi vì trình biên dịch không còn có thể tận dụng suy luận kiểu chung chung. – Daryl

4

Thực hiện trình biên dịch nhầm lẫn nhiều lần IEnumerable, mà IEnumerable <> nên xem xét việc này.

IEnumerable<Vehicle> or IEnumerable<Truck>? 

this.FirstOrDefault<Truck>() might compile. 
0

công cộng mới IEnumerator GetEnumerator()

Đó new từ khóa trong dòng da phương pháp GetEnumerator() được kế thừa từ lớp Vehicle. Tôi không chắc chắn điều này sẽ làm việc, nhưng có lẽ hãy thử explicit interface implementation thay thế.

+0

Sử dụng thực hiện giao diện rõ ràng cho một số giao diện và tiềm ẩn cho những người khác không thay đổi độ phân giải phương pháp mở rộng. Điều này chỉ giúp bạn trực tiếp gọi điện cho 'GetEnumerator() ', vì vậy điều này không hữu ích. – binki

7

Thay đổi mã của bạn để:

public class Trucks : Vehicles<Truck> 
{  
}  

public class Vehicles<T> : IEnumerable<T> 
    where T : Vehicle 
{  
}  

public class Vehicle { } 

public class Truck : Vehicle { } 
+0

chỉ cần một vài phút để làm chậm;) – Clayton

+0

@Clayton - đó là cuộc sống ;-) –

+0

tiếc là tôi không có quyền truy cập vào mã lớp cơ sở, nhưng đó sẽ là giải pháp đúng. Tôi sẽ phải xem liệu tôi có thể thực hiện thay đổi đó hay không. Cảm ơn! – Daryl

2

Hình như bạn đang mắc kẹt kinda. Đây là một gợi ý để giảm đánh máy của bạn. Bạn có thể tạo một phương thức mở rộng cho một số loại được sử dụng phổ biến của bạn trên IEnumerable <>.

var a = myList.AsTruckEnumerable().FirstOrDefault(); 

public static partial class Extensions 
{ 
    public static IEnumerable<Truck> AsTruckEnumerable (this IEnumerable<Truck> trucks) 
    { 
    return trucks; 
    } 
} 

public class Trucks<T> : Vehicles, IEnumerable<Truck> 
{  
    public Trucks() 
    {  
     // Does Compile 
     var a = ((IEnumerable<Truck>)this).FirstOrDefault(); 

     // Does compile 
     var b = this.AsTruckEnumerable().FirstOrDefault(); 
     // Doesn't Compile, Linq.FirstOrDefault not found 
     //var b = this.FirstOrDefault(); 
    }  

    public new IEnumerator<Truck> GetEnumerator() { throw new NotImplementedException(); } 
}  
Các vấn đề liên quan