C#: 在using语句中使用IEnumerator<T>

6

我很好奇看看MoreLinq中的SingleOrFallback方法是如何实现的,结果发现了一些之前没见过的东西:

    public static T SingleOrFallback<T>(this IEnumerable<T> source, Func<T> fallback)
    {
        source.ThrowIfNull("source");
        fallback.ThrowIfNull("fallback");
        using (IEnumerator<T> iterator = source.GetEnumerator())
        {
            if (!iterator.MoveNext())
            {
                return fallback();
            }
            T first = iterator.Current;
            if (iterator.MoveNext())
            {
                throw new InvalidOperationException();
            }
            return first;
        }
    }

为什么IEnumerator<T>using语句中?当使用IEnumerable<T>上的foreach时,这是否应该考虑?副问题:这个方法到底是做什么的?它是否在源序列不包含恰好一个项目时返回回退项目?
2个回答

11

IEnumerator<T> 继承自 IDisposable,因此您应该在使用语句中拥有它。 foreach会自动处理这一点。(非泛型的 IEnumerator 并未继承 IDisposable,但C#编译器仍会生成代码来有条件地调用Dispose。这是C# 1.0和1.2之间(少数)更改之一,其中1.2是随.NET 1.1一起发布的版本,出于某种原因。)

这里有一篇文章解释了在迭代器块的上下文中为什么这很重要。

至于该方法的功能:

  • 如果序列为空,则返回备用项
  • 如果序列恰好有一个项,则返回它
  • 如果序列有多个项,则抛出异常

附:很高兴看到 MoreLinq 正受到关注 :)


1
嘿嘿,是的。我们将它添加到项目中是因为MaxBy和MinBy方法。而且在添加类似的东西时,你总是要检查是否有其他可以使用的东西;) - Svish
不确定 SingleOrFallback 方法有何用处...您能解释一下您使用它的原因吗?现在理解它的功能了,但不知道什么情况下需要使用这种方法 :p - Svish
当你有一个搜索应该只返回单个结果(如果有的话)时,你想要对于如果没有返回任何结果设定默认值。但是如果有多个结果,则停止程序运行并报告错误(因为这表示有错误存在)。基本上,这就是带有指定的默认函数值的SingleOrDefault,除非需要,否则不会调用该函数。 - Jon Skeet
啊哈。但是SingleOrDefault也包含一个谓词,对吧?所以要使用这个SingleOrFallback,你可以例如使用Where(predicate),然后再使用SingleOrFallback。 - Svish
SingleOrDefault有一种带谓词的重载形式,是的。如果需要的话,我们也可以将其添加到SingleOrFallback中,但否则使用Where就可以了。 - Jon Skeet

0
一些枚举器如果没有调用Dispose方法会表现得很糟糕;这对于非泛型的枚举器和泛型的枚举器同样适用(非泛型的枚举器要求代码模拟Dispose调用或者将其强制转换为IDisposable并调用IDisposable.Dispose)。确保IEnumerator对象被处理是一个好习惯;我认为对于接受未知类型的IEnumerable的任何例程来说,这是必要的正确性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接