Как делегировать реализацию интерфейса другому классу в C # - PullRequest
8 голосов
/ 24 сентября 2008

Предположим, следующий класс:

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

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

Ответы [ 7 ]

7 голосов
/ 24 сентября 2008

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

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: Унаследовав от реализации List, вы получаете такое поведение бесплатно.

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 обеспечивает лучшую изолированную среду, так как в List нет метода, который был бы вызван без знания MyEnum. Для наименьшего усилия Метод 2 является предпочтительным.

1 голос
/ 24 сентября 2008

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

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

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

1 голос
/ 24 сентября 2008

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

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

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

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

0 голосов
/ 07 июня 2017

Обратите внимание, что благодаря 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 голосов
/ 24 сентября 2008

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

    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 голосов
/ 24 сентября 2008

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

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

0 голосов
/ 24 сентября 2008

Нет, если вы не производны от Списка .

public class MyEnum : List<SomeObject>, IEnumerable<SomeObject>{}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...