Как реализовать IEnumerable <T>

Я знаю, как реализовать не общий IEnumerable, например:

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

Однако я также заметил, что IEnumerable имеет общую версию IEnumerable<T>, но я не могу понять, как ее реализовать.

Если я добавлю using System.Collections.Generic; к моим используемым директивам, а затем измените:

class MyObjects : IEnumerable

чтобы:

class MyObjects : IEnumerable<MyObject>

Затем щелкните правой кнопкой мыши на IEnumerable<MyObject> и выберите " Implement Interface => Implement Interface, Visual Studio помогает добавить следующий блок кода:

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

Возврат не общего объекта IEnumerable из GetEnumerator(); метод не работает в этот раз, так что я здесь ставлю? CLI теперь игнорирует не общую реализацию и направляется прямо к общей версии, когда пытается перечислить мой массив во время цикла foreach.

Ответ 1

Если вы решили использовать общую коллекцию, такую как List<MyObject> вместо ArrayList, вы обнаружите, что List<MyObject> будет предоставлять как общие, так и не общие счетчики, которые вы можете использовать.

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

Ответ 2

Вероятно, вам не нужна явная реализация IEnumerable<T> (это то, что вы показали).

Обычным шаблоном является использование IEnumerable<T> GetEnumerator в явной реализации 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();
    }
}

Ответ 3

Почему вы делаете это вручную? yield return автоматизирует весь процесс обработки итераторов. (Я также писал об этом в своем блоге, включая просмотр кода, сгенерированного компилятором).

Если вы действительно хотите сделать это самостоятельно, вам также нужно вернуть общий счетчик. Вы больше не сможете использовать ArrayList с тех пор, пока это не является общим. Вместо этого замените его на List<MyObject>. Это, конечно, предполагает, что в вашей коллекции есть только объекты типа MyObject (или производные типы).

Ответ 4

Если вы работаете с дженериками, используйте List вместо ArrayList. Список имеет именно тот метод GetEnumerator, который вам нужен.

List<MyObject> myList = new List<MyObject>();

Ответ 5

сделать mylist в List<MyObject>, это один из вариантов