我知道如何实现非通用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;
添加到我的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();
方法返回非通用IEnumerable对象不起作用,那么我在这里放什么呢? CLI现在忽略非泛型实现,并在foreach循环期间尝试枚举我的数组时直接使用泛型版本。
答案 0 :(得分:137)
如果您选择使用通用集合,例如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();
}
}
答案 1 :(得分:54)
您可能不希望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();
}
}
答案 2 :(得分:24)
为什么要手动完成? yield return
自动化处理迭代器的整个过程。 (我也写过它on my blog,包括看一下编译器生成的代码。)
如果你真的想自己做,你也必须返回一个通用的枚举器。由于这是非通用的,您将无法再使用ArrayList
。将其更改为List<MyObject>
。当然,假设您的集合中只有MyObject
类型的对象(或派生类型)。
答案 3 :(得分:4)
如果使用泛型,请使用List而不是ArrayList。 List具有您需要的GetEnumerator方法。
List<MyObject> myList = new List<MyObject>();
答案 4 :(得分:0)
将mylist设为List<MyObject>
,是一个选项
答案 5 :(得分:-1)
请注意,IEnumerable<T>
已经由System.Collections
实现,因此另一种方法是从MyObjects
派生您的System.Collections
类作为基类(documentation) :
System.Collections:提供通用集合的基类。
我们稍后可以自己实现,以覆盖虚拟System.Collections
方法以提供自定义行为(仅适用于ClearItems
,InsertItem
,RemoveItem
和{{1} }以及SetItem
中的Equals
,GetHashCode
和ToString
)。与Object
不同,后者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
驱动,这种情况很少发生。参见usage。