2011-02-11 82 views
37

Sự khác nhau giữa IEnumerableIEnumerable<T> là gì?Sự khác nhau giữa IEnumerable và IEnumerable <T>?

Tôi đã thấy nhiều lớp khung công tác triển khai cả hai giao diện này, do đó tôi muốn biết những lợi ích nào có được bằng cách triển khai cả hai?

hãy có một cái nhìn như thế nào họ đã được xác định:

public interface IEnumerable 
{ 
    [DispId(-4)] 
    IEnumerator GetEnumerator(); 
} 
public interface IEnumerable<T> : IEnumerable 
{ 
    IEnumerator<T> GetEnumerator(); 
} 

Như chúng ta thấy, IEnumerable<T> xuất phát từ IEnumerable, có nghĩa là bất cứ điều gì IEnumerable có, IEnumerable<T> kế thừa, sau đó tại sao chúng ta thực hiện cả hai thay vì chỉ IEnumerable<T> ? Đang triển khai IEnumerable<T> chưa đủ?

Tương tự như vậy, có những cặp tương tự khác:

  • IListIList<T>
  • ICollectionICollection<T>

Tôi muốn biết về những là tốt.

Trả lời

48

Về cơ bản, giao diện nongeneric xuất hiện trước, trong .NET 1.0 và 1.1. Sau đó, khi .NET 2.0 ra đời, các tương đương chung xuất hiện. Cuộc sống có thể đã được đơn giản hơn rất nhiều nếu Generics đã làm cho nó vào NET 1.0 :)

Xét về thực hiện "chỉ" IEnumerable<T> thay vì cả hai - về cơ bản bạn để thực hiện cả hai, và bạn phải sử dụng giao diện rõ ràng thực hiện quá, cho rằng cả hai xác định một phương pháp không tham số GetEnumerator. Như IEnumerator<T> kéo dài IEnumerator quá, đó là bình thường một cái gì đó như thế này:

public IEnumerator<T> GetEnumerator() 
{ 
    // Return real iterator 
} 

// Explicit implementation of nongeneric interface 
IEnumerator IEnumerable.GetEnumerator() 
{ 
    // Delegate to the generic implementation 
    return GetEnumerator(); 
} 

Mặt khác, với các khối iterator giới thiệu trong C# 2 (với yield return vv), bạn hiếm khi cần phải thực hiện những điều này hoàn toàn bằng tay, may mắn thay. Bạn có thể cần phải viết một cái gì đó như trên, và sau đó sử dụng yield return trong phương pháp GetEnumerator.

Lưu ý rằng IList<T> không không mở rộng IList, và ICollection<T> không không mở rộng ICollection. Đó là bởi vì nó ít an toàn hơn để làm như vậy ... trong khi bất kỳ trình vòng lặp chung nào có thể được xem như là một trình lặp không đồng bộ do chuyển đổi (có khả năng đấm bốc) của bất kỳ giá trị nào thành object, IListICollection cho phép các giá trị được thêm vào bộ sưu tập; và không có ý nghĩa gì khi thêm (nói) một chuỗi vào một số IList<int>.

EDIT: Lý do tại sao chúng tôi cần IEnumerable<T> để chúng tôi có thể lặp lại theo cách an toàn, và truyền bá thông tin đó. Nếu tôi trả lại một số IEnumerable<string> cho bạn, bạn biết rằng bạn có thể giả định một cách an toàn mọi thứ được trả lại từ đó sẽ là tham chiếu chuỗi hoặc null. Với IEnumerable, chúng tôi phải đúc một cách hiệu quả (thường ngầm trong câu lệnh foreach) mỗi phần tử được trả lại từ chuỗi, vì thuộc tính Current của IEnumerator chỉ là loại object.Đối với lý do tại sao chúng tôi vẫn còn cần IEnumerable - về cơ bản vì giao diện cũ không bao giờ biến mất. Có quá nhiều mã đang sử dụng.

Nó đã có thể cho IEnumerable<T> không để kéo dài IEnumerable, nhưng sau đó bất kỳ mã muốn tận dụng một IEnumerable<T> không thể gọi thành một phương pháp chấp nhận IEnumerable - và đã có rất nhiều các phương pháp như thế từ .NET 1.1 và 1.0.

+12

+1 Cuộc sống sẽ đơn giản hơn rất nhiều nếu các generics đã tạo ra nó thành .NET 1.0 ... – Oded

+0

@Jon: câu hỏi đặt ra là: tại sao chúng ta cần phải thực hiện 'IEnumerable' khi chúng ta đã thực hiện 'IEnumerable ' , hoặc ngược lại? – Nawaz

+0

@Nawaz: Tôi đã chỉnh sửa câu trả lời của mình. Làm thế nào thoải mái là bạn với ý tưởng về lý do tại sao Generics là một điều tốt? –

5

Một trả về một đối tượng kiểu Object, lợi nhuận khác một đối tượng kiểu T.

2

Là tại sao bạn thấy lớp xác định cả hai, đủ mặc dù IEnumerable < T> thực hiện IEnumerable, nó không cần thiết nhưng là đẹp trong một tài liệu tự để liệt kê các giao diện phụ vào các thời điểm. Hãy xem xét

interface IA { } 
interface IB : IA { } 

class A : IB {} // legal, IB implements IA 

class B : IA, IB {} // also legal, possible more clear on intent 
1

Trong khi lặp qua vòng lặp, IEnumerator duy trì trạng thái. Nó nhớ vị trí con trỏ và IEnumerable thì không.

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