Как реализовать 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>
, это один из вариантов