我是否需要考虑处理我使用的任何IEnumerable <T>?

Rob*_*Rob 69 c# linq ienumerable dispose

它最近向我指出,各种LINQ的扩展方法(如Where,Select等)返回IEnumerable<T>,恰巧也有IDisposable.以下评估结果True

new int[2] {0,1}.Select(x => x*2) is IDisposable
Run Code Online (Sandbox Code Playgroud)

我是否需要处理Where表达式的结果?

每当我打电话给一个方法返回时IEnumerable<T>,我(可能)接受在我完成它时调用dispose的责任吗?

Jon*_*eet 83

不,你不必担心这个.

他们返回的事实IDisposable实现是一个实现细节-这是因为在微软实现C#编译器的迭代块发生创建一个单一的,它实现两个类型IEnumerable<T>IEnumerator<T>.后者延伸IDisposable,这就是你看到它的原因.

示例代码来演示此:

using System;
using System.Collections.Generic;

public class Test 
{
    static void Main() 
    {
        IEnumerable<int> foo = Foo();
        Console.WriteLine(foo is IDisposable); // Prints True
    }

    static IEnumerable<int> Foo()
    {
        yield break;
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您需要考虑的一个事实音符IEnumerator<T>实现IDisposable.因此,只要您明确迭代,就应该正确处理它.例如,如果你想迭代某些东西并确保你总是有一个值,你可以使用类似的东西:

using (var enumerator = enumerable.GetEnumerator())
{
    if (!enumerator.MoveNext())
    {
        throw // some kind of exception;
    }
    var value = enumerator.Current;
    while (enumerator.MoveNext())
    {
        // Do something with value and enumerator.Current
    }
}
Run Code Online (Sandbox Code Playgroud)

(foreach当然,循环会自动执行此操作.)

  • 所以如果我没有明确使用枚举器,我永远不需要处理? (2认同)
  • 有趣的是,在至少调用过一次 GetEnumerator() 的迭代器上调用 Dispose 将使第一次调用返回的枚举器无效,但不会使后续调用返回的任何枚举器无效;在第一个“GetEnumerator()”调用之前调用“Dispose”没有效果。 (2认同)
  • @ ean5533:第一次调用`GetEnumerator()`返回对同一引用的引用; 此后,它将创建单独的副本.我们的想法是仅在迭代一次的常见情况下创建单个对象. (2认同)