2

我正在开发一个集合类,它应该实现 IEnumerator 和 IEnumerable。

在我的第一种方法中,我直接实现了它们。现在我发现了 yield 关键字,并且我已经能够用一个只读属性 Values 替换 IEnumerator/IEnumerable 接口来简化一切,该属性使用 yield 在循环中返回一个 IEnumerable。

我的问题:是否可以在不实现 IEnumerable/IEnumerator 的情况下以可以迭代类本身的方式使用 yield?

即,我想要一个类似于框架集合的功能:

List<int> myList = new List<int>();
foreach (int i in myList)
{
    ...
}

这可能吗?

更新:看来我的问题措辞不当。我不介意实现 IEnumerator 或 IEnumerable;我只是认为唯一的方法是使用旧的 Current/MoveNext/Reset 方法。

4

2 回答 2

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。

于 2011-05-26T09:00:19.493 回答
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。

于 2011-05-26T09:32:10.757 回答