2013-09-05 30 views
5

Với ví dụ LinqPad sau:Tại sao IEnumerable không cần một dàn diễn viên nhưng Danh sách có?

void Main() 
{ 
    List<DbItem> dbItems = new List<DbItem> 
    { 
     new DbItem{Id = 4, SomeValue = "Value For 4", OtherValue = 1}, 
     new DbItem{Id = 19, SomeValue = "Value For 19", OtherValue = 2} 
    }; 

    ListMethod(dbItems.Cast<IDbItem>().ToList()); <-+ 
    EnumerableMethod(dbItems);      <-+ 
}              | 
                 | 
// These are the methods are I asking about -------+ 

public void ListMethod(List<IDbItem> dbItems) 
{ 
    Console.WriteLine(dbItems); 
} 
public void EnumerableMethod(IEnumerable<IDbItem> dbItems) 
{ 
    Console.WriteLine(dbItems); 
} 
public class DbItem : IDbItem 
{ 
    public int Id {get; set;} 
    public string SomeValue {get; set;} 
    public int OtherValue {get; set;} 
} 
public interface IDbItem 
{ 
    int Id {get; set;} 
    string SomeValue {get; set;} 
} 

Tại sao có thể EnumerableMethod mất danh sách trực tiếp trong khi ListMethod cần một dàn diễn viên đầu tiên?

Tôi nhận được rằng một diễn viên đang diễn ra từ DbItem đến IDbItem, nhưng điều gì khác biệt về IEnumerable cho phép nó tạo diễn viên mà không có yêu cầu rõ ràng?

Tôi tưởng tượng câu trả lời liên quan đến từ hiệp phương sai, nhưng tôi không biết đủ về điều đó để tự tìm ra.

Trả lời

4

Khám phá this post about covariance. Ông đưa ra một lời giải thích và một cách để làm cho mã hoạt động mà không có diễn viên. Danh sách không phải là biến thể, nhưng bạn chỉ có thể thay đổi phương thức như vậy:

public void ListMethod<T>(List<T> dbItems) where T : IDbItem 
{ 
    Console.WriteLine(dbItems); 
} 

Hiệp phương sai là khả năng gán loại chung có nguồn gốc cho loại chung chung. Lý do List không hiệp biến là bởi vì bạn có thể làm điều này:

class Animal {} 
class Dog : Animal {} 
class Cat : Animal {} 

void someFunction() 
{ 
    List<Animal> dogs = new List<Dog>(); 
    dogs.Add(new Cat()); 
} 

dogs thực sự là một danh sách các con chó, không phải động vật. Do đó, thêm Cat vào đó sẽ là một vấn đề, đặc biệt gây ra lỗi trình biên dịch.

+0

Tôi nhận được rằng một con chó thực sự là một danh sách các con chó và không động vật. Nhưng sau đó tại sao nó làm việc cho IEnumerable? – Vaccano

+0

'IEnumerable' không có phương thức' Add', do đó không sợ thêm 'Cat' vào' dogs'. Hiệp phương sai là một cái gì đó phải được xác định rõ ràng, và những kẻ tạo ra 'Danh sách' quyết định rằng nó không nên là biến đổi cho lý do trên. Những kẻ đã tạo ra 'IEnumerable' đã quyết định rằng nó phải là một biến thể. – ShadowCat7

0

Bởi vì bạn không thể đúc tập hợp x vào tập hợp của y, mặc dù x xuất phát từ y và do đó x là y. Xem this SO question.

Đây là lý do tại sao các khái niệm hiệp phương sai và các khái niệm contravariance đã được thêm vào ngôn ngữ.

Thật không may List<T> không hỗ trợ các tính năng này.

+0

.NET 4.0/C# 4.0 chỉ áp dụng cho các giao diện chung và các khai báo đại biểu chung; nó không áp dụng cho các loại bê tông (vì vậy nó không phải là một tính năng hỗ trợ của Danh sách, nhưng của tất cả các loại cụ thể). –

3

Tôi tưởng tượng ra câu trả lời liên quan đến từ Hiệp phương sai

Có bạn là chính xác, Tham số kiểu cho IEnumerable<T> là hiệp biến. vì vậy bạn có thể sử dụng một trong hai loại mà bạn chỉ định hoặc bất kỳ loại mà có nguồn gốc hơn

public interface IEnumerable<out T> : IEnumerable 

Trong trường hợp như List<T> loại tham số không được hiệp biến

public class List<T> : IList<T>, ICollection<T>, 
    IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, 
    IEnumerable 
+0

Từ khóa 'out' có làm cho biến thể IEnumerable không? Nếu vậy, tại sao? Nếu không, thì sao? – Vaccano

+0

Có, The out làm cho tham số kiểu covariant, tại sao? đó là câu hỏi cho các nhà thiết kế ngôn ngữ C# –

Các vấn đề liên quan