2010-12-28 9 views
7

Tôi sử dụng mã sau để cho phép myClass sử dụng foreach. Nhưng tôi khá mới để lập trình và gặp khó khăn trong việc hiểu mã sau đây. Tôi đã mô tả các vấn đề của tôi trong phần bình luận. Tôi sẽ biết ơn vì đã cung cấp một số thông tin.Câu hỏi liên quan đến IEnumerable và IEnumerator

public class MyClass : IEnumerable<string> 
    { 
    //1) What is IEnumerator for? 
     // Whats the difference between IEnumerator and IEnumerable 
    public IEnumerator<string> GetEnumerator()  
    { 
      yield return "first";   
      yield return "second";  
    }  
    //2) What is it for? It just calls above method 
    IEnumerator IEnumerable.GetEnumerator() 
     { 
      return GetEnumerator(); 
     } 
    } 
    //3) Lastly what benefits I have from implementing genetic interface 
    //IEnumerable<string> instead of just IEnumerable 
+3

Tôi sẽ để john skeet trả lời câu hỏi này –

+4

@ Hasan: Tôi sợ những gì anh ấy sẽ làm với bạn bằng cách viết sai chính tả tên của anh ấy. – JYelton

Trả lời

11

Sự khác nhau giữa IEnumerator và IEnumerable là gì?

Câu trả lời của Jason rất hay nhưng tôi nghĩ tôi chỉ cần thêm suy nghĩ về điều này. Hãy tưởng tượng bạn có một chuỗi:

1, 1, 2, 3, 5, 8, 13, ... 

Bây giờ hãy tưởng tượng bạn có một mũi tên trỏ tại một số vị trí của chuỗi rằng:

1, 1, 2, 3, 5, 8, 13, ... 
     ^

Một "mũi tên" là một đối tượng có thể làm hai việc. Đầu tiên, nó có thể cung cấp cho bạn thứ mà nó đang trỏ đến. Thứ hai, nó có thể làm cho chính nó chỉ vào điều tiếp theo.

Trình đếm số là một mũi tên. Nó có một thuộc tính, Current, cung cấp cho bạn thứ mà nó trỏ đến. Nó có một phương thức, MoveNext() làm cho chính nó trỏ đến điều tiếp theo.

Làm thế nào để bạn nhận được mũi tên ngay từ đầu? Bạn cần một nhà máy mũi tên. Bạn yêu cầu nhà máy cho một mũi tên, và nó cung cấp cho bạn một mũi tên trỏ đến phần tử đầu tiên trong chuỗi.

IEnumerable là một nhà máy mũi tên. Nó có một phương thức, GetEnumerator, cung cấp cho bạn một mũi tên đến phần tử đầu tiên của chuỗi.

Thuộc tính tốt đẹp của lược đồ này là bạn có thể có nhiều mũi tên trỏ đến các địa điểm khác nhau trong cùng một trình tự.

lợi ích của việc triển khai giao diện chung là gì IEnumerable thay vì chỉ IEnumerable?

Giả sử trình tự là số nguyên. Nếu bạn thực hiện IEnumerable sau đó khi bạn nói

foreach(int x in mysequence) 

điều đó sẽ thực sự làm là chuyển đổi int trong chuỗi phản đối, boxing số nguyên, và sau đó ngay lập tức Unbox đối tượng trở về nguyên, thêm một cấp phát bộ nhớ hoàn toàn không cần thiết cho mọi hoạt động đơn lẻ. Nếu trình biên dịch biết rằng trình tự là số nguyên thì nó có thể bỏ qua thao tác boxing không cần thiết.

Giả sử chuỗi là chuỗi. Nếu bạn thực hiện IEnumerable<string> sau đó bạn có thể nói:

string first = mysequence.First(); 

Nếu không, sau đó bạn có thể nói

string first = (string)mysequence.First(); 

đó là không cần thiết và dễ bị lỗi. Thay vì hướng dẫn trình biên dịch thông qua một dàn diễn viên rằng loại là chuỗi, bạn có thể chỉ cần bảo đảm rằng loại đó là chuỗi bằng cách sử dụng hệ thống kiểu.

+2

Ẩn dụ tuyệt vời với khái niệm mũi tên. Nó cũng có thể đáng nói đến là một tác dụng phụ phổ biến của mô hình này là việc thay đổi bộ sưu tập bắt đầu liệt kê thường làm mất hiệu lực tất cả các "mũi tên" chỉ vào nó. – LBushkin

+0

Ghi chú nhỏ về _ "GetEnumerator, cung cấp cho bạn một mũi tên đến phần tử đầu tiên của chuỗi" _: Theo [MSDN] (http://msdn.microsoft.com/en-us/library/system.collections.ienumerable .getenumerator (v = vs.110) .aspx), nó cung cấp cho bạn một mũi tên trỏ đến một số điều không xác định _before_ điều đầu tiên. – jan

+0

@jan: Tốt! –

0

GetEnumerator đã có từ trước khi generics được giới thiệu với ngôn ngữ, để không phá vỡ mã đã tồn tại, phương thức mặc định gọi đến thực hiện chung.

Với điều tra chung, người tiêu dùng lớp học của bạn không cần phải bỏ từng mục vào chuỗi khi lặp lại.

6

1) IEnumerator là gì? Whats sự khác biệt giữa IEnumeratorIEnumerable là gì?

IEnumerator là giao diện đại diện cho các phương pháp cho phép bạn liệt kê chuỗi. Sự khác biệt giữa IEnumeratorIEnumerable là trước đây đại diện cho hợp đồng cho các đối tượng cho phép bạn liệt kê một chuỗi và thứ hai thể hiện hợp đồng cho các đối tượng là chuỗi có thể được liệt kê.

public IEnumerator<string> GetEnumerator() { 
     yield return "first";   
     yield return "second";  
}  


IEnumerator IEnumerable.GetEnumerator() { 
    return GetEnumerator(); 
} 

2) Cái này dùng để làm gì? Nó chỉ gọi phương thức trên.

Phần trước đại diện cho việc triển khai phương thức GetEnumerator trên hợp đồng IEnumerable<string>. Cái sau đại diện cho việc thực hiện rõ ràng phương thức GetEnumerator trên hợp đồng IEnumerable. Vấn đề là cả hai hợp đồng có một phương thức có tên là GetEnumerator nhưng với các kiểu trả về khác nhau để một phương thức không thể thỏa mãn đồng thời cả hai hợp đồng (bất kỳ lớp nào thực hiện IEnumerable<T> cũng phải thực hiện IEnumerableIEnumerable<T> : IEnumerable). Sau này gọi thực hiện IEnumerable<string>.GetEnumerator vì đó là một triển khai hợp lý trả về một IEnumeratorIEnumerator<string> : IEnumerator.

3) Cuối cùng tôi có lợi ích gì khi triển khai giao diện chung IEnumerable<string> thay vì chỉ IEnumerable?

Nhập mạnh. Bạn biết rằng các phần tử trong một chuỗi IEnumerable<string> là tất cả các trường hợp của String trong khi bạn không biết rằng đối với IEnumerable và có thể kết thúc cố gắng truyền một phần tử của phần tử sau vào một phiên bản String khi không thể.

3

1) IEnumerator là gì?

IEnumerator là bộ phận làm việc thực sự với các thành viên MoveNext() và hiện tại.

Whats sự khác biệt giữa IEnumerator và IEnumerable

IEnumerable là giao diện cho một bộ sưu tập để báo hiệu rằng nó có một GetEnumerator().

2) [không chung chung GetEnumerator] Nó là gì? Nó chỉ gọi phương thức trên

Phương pháp không chung chung chỉ có khả năng tương thích ngược. Lưu ý rằng nó được di chuyển 'ngoài tầm nhìn' càng nhiều càng tốt bằng cách sử dụng việc triển khai rõ ràng. Thực hiện nó bởi vì bạn phải và sau đó quên nó đi.

3) Cuối cùng những lợi ích tôi có từ việc thực hiện giao diện di truyền IEnumerable thay vì chỉ IEnumerable

Khi sử dụng với foreach các adavantage là nhỏ, như foreach sẽ gõ-cast biến vòng lặp. Nó sẽ cho phép bạn sử dụng var trong foreach:

foreach (var s in myClassInstance)  // needs `IEnumerable<string>` 
foreach (string s in myClassInstance) // works with `IEnumerable` as well 

Nhưng với IEnumerable<string> bạn cũng có một giao diện kiểu an đến khu vực khác, đáng chú ý nhất LINQ:

MyClass mc = new MyClass(); 
string s = mc.FirstOrDefault(); 
3

Đây là tuyên bố cho IEnumerable<T>:

public interface IEnumerable<out T> : IEnumerable 
{ 
    IEnumerator<T> GetEnumerator(); 
} 

bạn không có sự lựa chọn, bạn có để thực hiện các trình duyệt IE không chung giao diện số cũng được. Bạn sẽ nhận được một lỗi biên dịch nếu bạn bỏ qua việc thực hiện IEnumerable.GetEnumerator(). Đây là hành lý còn lại từ ngày .NET 1.x, nơi generics không có sẵn và giai đoạn chuyển tiếp cho .NET 2.0, nơi nó cần hỗ trợ interop với các hội đồng .NET 1.x. Chúng tôi đang mắc kẹt với nó.