2008-09-24 4 views
8

Пусть следующий класс:Как делегировать реализацию интерфейса к другому классу в C#

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

Необходимо реализовать методы IEnumerator в MyEnum. Но возможно ли делегировать или перенаправить реализацию IEnumerator непосредственно на _myList без необходимости применения методов IEnumerator?

ответ

7

Способ 1: Продолжить использование инкапсуляции и переадресации вызовов в реализацию списка.

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(); 
    } 
} 

Метод 2: Наследовать от реализации списка вы получите, что поведение бесплатно.

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(); 
    } 
} 

Метод 1 позволяет лучше песочницу, так как не существует метода, который будет вызываться в список без MyEnum знаний. Для наименьших усилий Способ 2 является предпочтительным.

-1

Если вы не получили из списка < T>.

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

Хорошо, это будет работать, но я хочу быть уверенным, что вызывающий код не в состоянии типа литья перечислитель перечислит снова и добавит или удалит из него объекты. – Willem 2008-09-24 09:23:46

1

Вы можете сделать это:

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

Причина проста. Ваш класс может содержать несколько полей, которые являются коллекциями, поэтому компилятор/среда не могут знать, какое поле должно использоваться для реализации «IEnumerator».

Eidt: Я согласен с @pb - вы должны реализует > интерфейс IEnumerator < SomeObject.

+0

Интерфейс для реализации IEnumerable не IEnumerator. – 2008-09-24 09:28:39

0

Если вы хотите вернуть коллекцию в пути, где абонент не может изменить коллекцию, вы можете обернуть список в ReadOnlyCollection <> и вернуть IEnumerable <> из ReadOnlyCollection <>.

Таким образом, вы можете быть уверены, что ваша коллекция не будет изменена.

1

Помимо использования метода pb, это невозможно для «простой» причины: метод интерфейса должен получить передатчик this в качестве первого аргумента. Когда вы вызываете GetEnumerator на свой объект, этот указатель будет вашим объектом. Однако для того, чтобы вызов работал во вложенном списке, указатель должен был бы ссылаться на этот список, а не на ваш класс.

Поэтому вы явно должны делегировать метод другому объекту.

(И, кстати, совет в другой ответ был прав: использование IEnumerator<T>, неIEnumerable!)

-1

Спасибо всем за ваш вклад и объяснения. В конце концов я объединил некоторые из ваших ответов на следующее:

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(); 
    } 
} 

Это решение для обеспечения код вызова не в состоянии изменения списка и каждый переписчик является независим от других во всех отношениях (например, с сортировкой) , Еще раз спасибо.

+0

Вы можете передать `ReadOnlyCollection`, потому что` IEnumerable `неизменны в любом случае! Пользователь должен обновить и угадать исходный тип списка, чтобы его изменить. Копирование списка IMHO не очень хорошая идея. – 2008-09-24 14:22:23

-1

Обратите внимание, что благодаря duck-typing, вы можете использовать foreach на любой объект, который имеет метод GetEnumerator - тип объекта не обязательно на самом деле реализации IEnumerable.

Так что, если вы сделаете это:

class SomeObject 
{ 
} 

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

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

Тогда это работает просто отлично:

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

Я понимаю, что это не общий ответ на исходный вопрос, но он имеет отношение к конкретному варианту использования, указанному в вопросе. – yoyo 2017-06-07 20:43:02