【问题标题】:Simple way to implement a Collection?实现集合的简单方法?
【发布时间】:2011-09-02 10:08:25
【问题描述】:

我正在开发一个集合类,它应该实现 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 方法。

【问题讨论】:

  • 我想不出任何理由这是个好主意。我缺乏想象力吗? IEnumerator 不是一个复杂或繁重的接口。
  • @Jodrell:让事情变得更简单不是一个好主意吗?为什么?
  • 你为什么认为你的收藏应该实现IEnumerator&lt;T&gt;
  • 更简单几乎总是更好,但我无法想象比 IEnumerator 的实现更简单的答案。
  • 嗯...对不起,伙计们,我认为使用 yield 来实现 IEnumerable 是不可能的。不实现 IEnumerator 或 IEnumerable 并不是真正的要求,我只是想要一些比旧的 Current/Reset/MoveNext 更简单的东西,这让我在调用之间保持状态,除了最简单的事情之外可能非常麻烦。

标签: c# .net ienumerable yield ienumerator


【解决方案1】:

您不会实施IEnumerable&lt;T&gt;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&lt;T&gt; 的替代方案只会调用您的Values 属性,但仍提供GetEnumerator() 方法:

public class Foo
{
    public IEnumerator<Bar> GetEnumerator()
    {
        // Use yield return here, or 
        // just return Values.GetEnumerator()
    }
]

虽然这可行,但这意味着您将无法将您的集合传递给任何期望 IEnumerable&lt;T&gt; 的对象,例如 LINQ to Objects。

这是一个鲜为人知的事实,foreach 将适用于任何支持 GetEnumerator() 方法的类型,该方法返回具有适当 MoveNext()Current 成员的类型。这实际上是为了在泛型之前允许强类型集合,其中迭代集合不会将值类型装箱等。现在真的不需要它,IMO。

【讨论】:

  • 感谢您快速而完整的回答。出于某种原因,我认为 yield 只能用于返回 IEnumerable。
  • @Jaime:如果你去manning.com/skeet,你仍然可以免费获得C#第一版的第6章。那一章都是关于迭代器块的:)
  • @Jodrell:第 8 章,你不妨从manning.com/skeet2获得第二版(仍然免费)
  • @Jon:谢谢,这些示例章节看起来很棒。你的书有西班牙语版吗?
  • @Jaime:据我所知,恐怕不是 :(
【解决方案2】:

你可以做这样的事情,但为什么呢? 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。

【讨论】:

  • 抱歉造成误会。如上所述,我认为不可能用 yield 实现 IEnumerator,但现在我知道得更好,我不介意这样做:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-07
  • 1970-01-01
  • 2010-09-11
相关资源
最近更新 更多