如何实现 IEnumable < T >

我知道如何实现非泛型 IEnumable,如下所示:

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

但是我也注意到 IEnumable 有一个通用版本 IEnumerable<T>,但是我不知道如何实现它。

如果我将 using System.Collections.Generic;添加到我的 using 指令中,然后更改:

class MyObjects : IEnumerable

致:

class MyObjects : IEnumerable<MyObject>

然后右键单击 IEnumerable<MyObject>并选择 Implement Interface => Implement Interface,Visual Studio 很有帮助地添加了以下代码块:

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

GetEnumerator();方法返回非泛型 IEnumable 对象这次不起作用,那么我在这里放什么呢?CLI 现在忽略非泛型实现,并在 foreach 循环期间尝试枚举数组时直奔泛型版本。

170162 次浏览

你为什么要手动操作?yield return使处理迭代器的整个过程自动化。(我还写了关于 在我的博客上的文章,包括看一下编译器生成的代码)。

如果你真的想自己做,你必须返回一个通用枚举器了。您将不能再使用 ArrayList,因为它是非通用的。改为 List<MyObject>。当然,这是假设您的集合中只有类型为 MyObject(或派生类型)的对象。

将 mylist 设置为 List<MyObject>是一种选择

您可能不希望 IEnumerable<T>露骨实现(这就是您所展示的)。

通常的模式是在 IEnumerable的显式实现中使用 IEnumerable<T>GetEnumerator:

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

如果使用泛型,请使用 List 而不是 ArrayList。 List 正好具有您需要的 GetEnumerator 方法。

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

如果您选择使用泛型集合,例如 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();
}
}

请注意,IEnumerable<T>已经由 System.Collections实现,因此另一种方法是从 System.Collections派生 MyObjects类作为基类(文件) :

System.Collections: 为泛型集合提供基类。

稍后,我们可以制作自己的实现来覆盖虚拟 System.Collections方法以提供定制行为(仅针对 ClearItemsInsertItemRemoveItemSetItem以及来自 ObjectEqualsGetHashCodeToString)。与 List<T>不同,List<T>的设计目的是不易扩展。

例如:

public class FooCollection : System.Collections<Foo>
{
//...
protected override void InsertItem(int index, Foo newItem)
{
base.InsertItem(index, newItem);
Console.Write("An item was successfully inserted to MyCollection!");
}
}


public static void Main()
{
FooCollection fooCollection = new FooCollection();
fooCollection.Add(new Foo()); //OUTPUT: An item was successfully inserted to FooCollection!
}

请注意,只有在需要自定义收集行为的情况下才建议从 collection驱动,这种情况很少发生。见 用途