Как делегировать реализацию интерфейса другому классу В 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 предпочтительнее.


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

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

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

EIDT: Я согласен с @pb-вы должны реализовать интерфейс IEnumerator.


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

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

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


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

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


нет, если вы не производны от List.

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

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

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

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


обратите внимание, что благодаря утка-типирование, вы можете использовать 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());
}