【问题标题】:Implement Enumerator.GetNext() extension method实现 Enumerator.GetNext() 扩展方法
【发布时间】:2014-04-18 01:10:10
【问题描述】:

我想实现一个通用的IEnumerator<T> 扩展方法,它返回IEnumerable 中的下一个元素,如下所示:

var list = new List<MyClass>();
var enumerator = list.GetEnumerator();

var nextItem1 = enumerator.GetNext();
var nextItem2 = enumerator.GetNext();

// Instead of calling enumerator.MoveNext() and then reading the current item.

我试图这样做,但它不会编译:

public static T GetNext(this IEnumerator<T> list)
{
     list.MoveNext();
     return list.Current;
}

我哪里做错了?谢谢。

【问题讨论】:

  • 你得到什么编译器错误?仅仅说您的代码无法编译并不能提供足够的信息来说明可能出现的问题。另外,你的类是如何定义的?
  • MoveNext返回false时,你的GetNext应该返回什么?
  • 异常。请参阅我在所选答案下的最后一条评论。它(尝试)解释用例。

标签: c# extension-methods ienumerable


【解决方案1】:

您似乎缺少方法签名上的泛型类型定义:

public static T GetNext<T>(this IEnumerator<T> list)
{
    // ---- this bit---^^^
}

假设没有同名的类级别泛型类型,它需要存在。否则它看起来很好。

不过……

我个人不会这样做,因为您没有听到MoveNext 的结果。除非您可以对预期值做出假设,否则您无法判断迭代器是否到达集合的末尾。对于最常见的用途,这不是一种可行的方法。

我实际上走了另一条路,实现了一个简单地手动迭代的AsEnumerable 扩展方法,但从外部允许您执行foreach (var item in iterator.AsEnumerable()) 之类的操作,并且不会忽略MoveNext 结果:

public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerator<TSource> iterator)
{
    while (iterator.MoveNext())
    {
        yield return iterator.Current;
    }
}

【讨论】:

  • 你不知道它何时结束迭代是对的,但就我而言,我仍然需要它以这种方式工作。我正在使用它来呈现带有表格的 cshtml 模板,其中标头的数量在 HTML 中定义,但每个标头从通过枚举列表发送的枚举描述属性加载其名称。我只是想避免创建一个完整的 Table ViewModel 并让表完全动态呈现,同时我想在一个地方定义标题的名称(枚举属性),因为这个相同的枚举在其他地方使用。
  • @UriAbramson 您可能会遇到解决方案可以工作的情况,因为根据您返回的值,您可能能够测试迭代可能何时结束(例如遇到空值)。我只是想向其他读者发布警告,这就是为什么我坚持说“这是错误的方式”。不是,这只是一种有局限性的方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-25
  • 1970-01-01
  • 1970-01-01
  • 2015-01-28
  • 2013-07-03
相关资源
最近更新 更多