我正在开发一个集合类,它应该实现IEnumerator和IEnumerable。
在我的第一种方法中,我直接实施了它们。现在我已经发现了yield关键字,并且我已经能够简化所有内容,将IEnumerator / IEnumerable接口替换为readonly属性,使用yield返回循环中的IEnumerable。
我的问题:是否有可能以这样的方式使用yield,我可以迭代类本身,而无需实现IEnumerable / IEnumerator?
即,我希望有一个类似于框架集合的功能:
List<int> myList = new List<int>();
foreach (int i in myList)
{
...
}
这有可能吗?
更新:似乎我的问题措辞严厉。我不介意实现IEnumerator或IEnumerable;我只是认为唯一的方法是使用旧的Current / MoveNext / Reset方法。
答案 0 :(得分:9)
您不会 实施IEnumerable<T>
或IEnumerable
以使foreach
工作 - 但这样做是个好主意。这很容易做到:
public class Foo : IEnumerable<Bar>
{
public IEnumerator<Bar> GetEnumerator()
{
// Use yield return here, or
// just return Values.GetEnumerator()
}
// Explicit interface implementation for non-generic
// interface; delegates to generic implementation.
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
不实施IEnumerable<T>
的替代方案只会调用您的Values
属性,但仍提供GetEnumerator()
方法:
public class Foo
{
public IEnumerator<Bar> GetEnumerator()
{
// Use yield return here, or
// just return Values.GetEnumerator()
}
]
虽然这样可行,但这意味着您将无法将集合传递给期望IEnumerable<T>
的任何内容,例如LINQ to Objects。
一个鲜为人知的事实是,foreach
适用于支持GetEnumerator()
方法的任何类型,该方法返回具有适当MoveNext()
和Current
成员的类型。这实际上是允许在泛型之前使用强类型集合,其中迭代集合不会包含值类型等。现在真的没有调用它,IMO。
答案 1 :(得分:1)
你可以这样做,但为什么呢? IEnumerator
已经很简单了。
Interface MyEnumerator<T>
{
public T GetNext();
}
public static class MyEnumeratorExtender
{
public static void MyForeach<T>(this MyEnumerator<T> enumerator,
Action<T> action)
{
T item = enumerator.GetNext();
while (item != null)
{
action.Invoke(item);
item = enumerator.GetNext();
}
}
}
我宁愿拥有in
关键字,我也不想重写linq。