2012-07-02 36 views
86

tôi biết làm thế nào để thực hiện các phi chung IEnumerable, như thế này:Làm thế nào để thực hiện IEnumerable <T>

using System; 
using System.Collections; 

namespace ConsoleApplication33 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MyObjects myObjects = new MyObjects(); 
      myObjects[0] = new MyObject() { Foo = "Hello", Bar = 1 }; 
      myObjects[1] = new MyObject() { Foo = "World", Bar = 2 }; 

      foreach (MyObject x in myObjects) 
      { 
       Console.WriteLine(x.Foo); 
       Console.WriteLine(x.Bar); 
      } 

      Console.ReadLine(); 
     } 
    } 

    class MyObject 
    { 
     public string Foo { get; set; } 
     public int Bar { get; set; } 
    } 

    class MyObjects : IEnumerable 
    { 
     ArrayList mylist = new ArrayList(); 

     public MyObject this[int index] 
     { 
      get { return (MyObject)mylist[index]; } 
      set { mylist.Insert(index, value); } 
     } 

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

Tuy nhiên tôi cũng nhận thấy rằng IEnumerable có một phiên bản generic, IEnumerable<T>, nhưng tôi không thể tìm ra cách để thực hiện nó.

Nếu tôi thêm using System.Collections.Generic; để chỉ sử dụng của tôi, và sau đó thay đổi:

class MyObjects : IEnumerable 

tới:

class MyObjects : IEnumerable<MyObject> 

Và sau đó nhấp chuột phải vào IEnumerable<MyObject> và chọn Implement Interface => Implement Interface, Visual Studio helpfully thêm khối sau của mã:

IEnumerator<MyObject> IEnumerable<MyObject>.GetEnumerator() 
{ 
    throw new NotImplementedException(); 
} 

Returni ng đối tượng IEnumerable không chung từ phương thức GetEnumerator(); không hoạt động vào lúc này, vì vậy tôi đặt gì ở đây? CLI bây giờ bỏ qua việc thực hiện không chung chung và đi thẳng cho phiên bản chung khi nó cố gắng liệt kê thông qua mảng của tôi trong vòng lặp foreach.

Cảm ơn

Trả lời

107

Nếu bạn chọn sử dụng một bộ sưu tập chung chung, chẳng hạn như thay vì List<MyObject>ArrayList, bạn sẽ thấy rằng List<MyObject> sẽ cung cấp cho điều tra viên cả hai chung chung và không chung chung mà bạn có thể sử dụng.

using System.Collections; 

class MyObjects : IEnumerable<MyObject> 
{ 
    List<MyObject> mylist = new List<MyObject>(); 

    public MyObject this[int index] 
    { 
     get { return mylist[index]; } 
     set { mylist.Insert(index, value); } 
    } 

    public IEnumerator<MyObject> GetEnumerator() 
    { 
     return mylist.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return this.GetEnumerator(); 
    } 
} 
+0

Trong việc thực hiện không chung chung, có một sự khác biệt giữa trả về 'this.GetEnumerator()' và chỉ đơn giản là trả về 'GetEnumerator()'? –

+0

@TannerSwett Không có sự khác biệt. –

20

Tại sao bạn làm điều đó theo cách thủ công? yield return tự động hóa toàn bộ quá trình xử lý các trình lặp. (Tôi cũng đã viết về nó on my blog, bao gồm cả việc xem mã trình biên dịch tạo ra).

Nếu bạn thực sự muốn tự mình làm, bạn phải trả lại một điều tra chung chung. Bạn sẽ không thể sử dụng thêm ArrayList nữa vì đó không phải là chung chung. Thay đổi nó thành một List<MyObject> thay thế. Điều đó tất nhiên giả định rằng bạn chỉ có các đối tượng thuộc loại MyObject (hoặc các loại có nguồn gốc) trong bộ sưu tập của bạn.

+2

+1, cần lưu ý rằng mẫu ưa thích là triển khai giao diện chung và triển khai rõ ràng giao diện không chung chung. Lợi nhuận trở lại là giải pháp tự nhiên nhất đối với giao diện chung. – user7116

+4

Trừ khi OP sẽ thực hiện một số xử lý trong điều tra viên, bằng cách sử dụng trả về lợi nhuận, chỉ cần thêm chi phí của một máy trạng thái khác. OP chỉ nên trả lại một điều tra viên được cung cấp bởi một bộ sưu tập chung cơ bản. –

+0

@MonroeThomas: Bạn nói đúng. Tôi đã không đọc kỹ câu hỏi này trước khi viết về 'lợi nhuận'. Tôi giả định sai rằng có một số xử lý tùy chỉnh. –

0

làm mylist thành một List<MyObject>, là một lựa chọn

38

Bạn có lẽ không muốn một rõ ràng thi hành IEnumerable<T> (đó là những gì bạn đã được hiển thị).

Các mô hình thông thường là sử dụng GetEnumerator IEnumerable<T> 's trong việc thực hiện rõ ràng của IEnumerable:

class FooCollection : IEnumerable<Foo>, IEnumerable 
{ 
    SomeCollection<Foo> foos; 

    // Explicit for IEnumerable because weakly typed collections are Bad 
    System.Collections.IEnumerator IEnumerable.GetEnumerator() 
    { 
     // uses the strongly typed IEnumerable<T> implementation 
     return this.GetEnumerator(); 
    } 

    // Normal implementation for IEnumerable<T> 
    IEnumerator<Foo> GetEnumerator() 
    { 
     foreach (Foo foo in this.foos) 
     { 
      yield return foo; 
      //nb: if SomeCollection is not strongly-typed use a cast: 
      // yield return (Foo)foo; 
      // Or better yet, switch to an internal collection which is 
      // strongly-typed. Such as List<T> or T[], your choice. 
     } 

     // or, as pointed out: return this.foos.GetEnumerator(); 
    } 
} 
+1

Đây là giải pháp tốt nếu SomeCollection chưa triển khai IEnumerable hoặc nếu bạn cần chuyển đổi hoặc thực hiện xử lý khác trên từng phần tử trước khi được trả về trong chuỗi liệt kê. Nếu không có điều kiện nào trong số này là đúng, thì có lẽ hiệu quả hơn để trả về this.foos.GetEnumerator(); –

+0

@MonroeThomas: đã đồng ý. Không có đầu mối những gì bộ sưu tập OP đang sử dụng. – user7116

+4

Điểm tốt. Nhưng việc thực thi 'IEnumerable' là thừa (' IEnumerable 'đã được thừa kế từ nó). – rsenna

3

Nếu bạn làm việc với Generics, sử dụng Danh sách thay vì ArrayList. Danh sách có chính xác phương thức GetEnumerator mà bạn cần.

List<MyObject> myList = new List<MyObject>(); 
Các vấn đề liên quan