2008-09-24 31 views
8

Giả sử lớp sau:Làm thế nào để thực hiện ủy thác giao diện đến lớp khác trong C#

public class MyEnum: IEnumerator 
{ 
    private List<SomeObject> _myList = new List<SomeObject>(); 
... 
} 

Nó là cần thiết để thực hiện các phương pháp IEnumerator trong MyEnum. Nhưng có thể 'ủy thác' hoặc chuyển hướng thực hiện cho IEnumerator trực tiếp tới _myList mà không cần triển khai các phương thức của IEnumerator không?

Trả lời

7

Phương pháp 1: Tiếp tục sử dụng gói gọn và chuyển tiếp cuộc gọi đến triển khai Danh sách.

class SomeObject 
{ 
} 

class MyEnum : IEnumerable<SomeObject> 
{ 
    private List<SomeObject> _myList = new List<SomeObject>(); 

    public void Add(SomeObject o) 
    { 
     _myList.Add(o); 
    } 

    public IEnumerator<SomeObject> GetEnumerator() 
    { 
     return _myList.GetEnumerator(); 
    } 

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

class Program 
{ 
    static void Main(string[] args) 
    { 
     MyEnum a = new MyEnum(); 
     a.Add(new SomeObject()); 

     foreach (SomeObject o in a) 
     { 
      Console.WriteLine(o.GetType().ToString()); 
     } 

     Console.ReadLine(); 
    } 
} 

Cách 2: Kế thừa từ Danh sách thực hiện bạn sẽ có được hành vi đó miễn phí.

class SomeObject 
{ 
} 

class MyEnum : List<SomeObject> 
{ 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     MyEnum a = new MyEnum(); 
     a.Add(new SomeObject()); 

     foreach (SomeObject o in a) 
     { 
      Console.WriteLine(o.GetType().ToString()); 
     } 

     Console.ReadLine(); 
    } 
} 

Phương pháp 1 cho phép sandboxing tốt hơn là không có phương pháp sẽ được gọi trong Danh sách mà bạn không biết MyEnum. Ít nhất nỗ lực Phương pháp 2 được ưu tiên.

-1

Không trừ khi bạn lấy được từ Danh sách < T>.

public class MyEnum : List<SomeObject>, IEnumerable<SomeObject>{} 
+0

Ok, điều này sẽ làm việc nhưng tôi muốn chắc chắn rằng mã gọi là không có khả năng loại đúc điều tra danh sách một lần nữa và thêm hoặc loại bỏ các đối tượng từ nó. – Willem

1

Bạn có thể làm điều này:

public class MyEnum : IEnumerator { 
    private List<SomeObject> _myList = new List<SomeObject>(); 
    public IEnumerator GetEnumerator() { return this._myList.GetEnumerator(); } 
} 

Lý do rất đơn giản. Lớp của bạn có thể chứa một số trường là bộ sưu tập, do đó trình biên dịch/môi trường không thể biết trường nào nên được sử dụng để triển khai "IEnumerator".

Chỉ cần nạp: Tôi đồng ý với @pb - bạn nên thực hiện giao diện IEnumerator <SomeObject>.

+0

Giao diện thực hiện là IEnumerable chứ không phải IEnumerator. –

0

Nếu bạn muốn trả về một bộ sưu tập theo một cách mà người gọi là không thể sửa đổi các bộ sưu tập, bạn có thể muốn quấn Danh sách thành ReadOnlyCollection <> và gửi lại IEnumerable <> của ReadOnlyCollection <>.

Bằng cách này bạn có thể chắc chắn rằng bộ sưu tập của bạn sẽ không bị thay đổi.

1

Ngoài việc sử dụng phương pháp của pb, điều này là không thể vì lý do “đơn giản”: phương thức giao diện cần được chuyển một con trỏ this làm đối số đầu tiên. Khi bạn gọi GetEnumerator trên đối tượng của bạn, con trỏ này sẽ là đối tượng của bạn. Tuy nhiên, để lời gọi làm việc trên danh sách lồng nhau, con trỏ sẽ phải là một tham chiếu đến danh sách đó, không phải là lớp của bạn.

Do đó bạn rõ ràng phải ủy quyền phương thức cho đối tượng khác.

(Và bằng cách này, những lời khuyên trong bài trả lời khác đã đúng: sử dụng IEnumerator<T>, khôngIEnumerable!)

-1

Cảm ơn tất cả các bạn cho đầu vào và giải thích của bạn. Cuối cùng tôi đã kết hợp một số câu trả lời của bạn như sau:

class MyEnum : IEnumerable<SomeObject> 
{ 
    private List<SomeObject> _myList = new List<SomeObject>(); 
    public IEnumerator<SomeObject> GetEnumerator() 
    { 
     // Create a read-only copy of the list. 
     ReadOnlyCollection<CustomDevice> items = new ReadOnlyCollection<CustomDevice>(_myList); 
     return items.GetEnumerator(); 
    } 
} 

Giải pháp này là để đảm bảo mã gọi là không có khả năng sửa đổi danh sách và mỗi điều tra viên là độc lập của những người khác trong mọi phương diện (ví dụ với phân loại) . Cảm ơn bạn lần nữa.

+0

Bạn có thể vượt qua 'ReadOnlyCollection' vì' IEnumerable 'là bất biến! Người dùng phải upcast và đoán kiểu gốc của danh sách để sửa đổi nó. Sao chép danh sách là IMHO không phải là một ý tưởng rất tốt. –

-1

Lưu ý rằng nhờ duck-typing, bạn có thể sử dụng foreach trên bất kỳ đối tượng nào có phương thức GetEnumerator - loại đối tượng không thực sự cần thực hiện IEnumerable.

Vì vậy, nếu bạn làm điều này:

class SomeObject 
{ 
} 

class MyEnum 
{ 
    private List<SomeObject> _myList = new List<SomeObject>(); 

    public IEnumerator<SomeObject> GetEnumerator() 
    { 
     return _myList.GetEnumerator(); 
    } 
} 

Sau đó này chỉ hoạt động tốt:

MyEnum objects = new MyEnum(); 
// ... add some objects 
foreach (SomeObject obj in objects) 
{ 
    Console.WriteLine(obj.ToString()); 
} 
+0

Tôi nhận thấy đây không phải là câu trả lời chung cho câu hỏi ban đầu, nhưng nó có liên quan đến trường hợp sử dụng cụ thể được cung cấp trong câu hỏi. – yoyo

+0

Nếu bạn nhận ra rằng bạn không trả lời câu hỏi thì * không đăng câu trả lời cho câu hỏi *. Câu trả lời là để trả lời câu hỏi, không phải để đăng các sự kiện ngẫu nhiên tầm thường mà bạn thấy thú vị. Điều này không thực sự giúp bạn trong tình huống này; không có lý do gì để bạn không thực sự triển khai giao diện trong tình huống này. – Servy

+0

Câu hỏi đặt ra là cách ủy quyền thực hiện giao diện để tránh viết mã bản mẫu. Câu trả lời của tôi là một câu trả lời tiềm năng cho trường hợp phổ biến của việc ủy ​​nhiệm việc thực hiện IEnumerable, cũng là ví dụ được OP sử dụng. Tôi đã tranh luận liệu có nên đưa ra nhận xét hay câu trả lời hay không, và quyết định làm cho nó là một câu trả lời. Nó * là * một câu trả lời cho một dạng câu hỏi cụ thể. – yoyo

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