如何取消IEnumerable?

maf*_*afu 5 .net c# ienumerable

在返回的方法中IEnumerable<>,我打开并循环遍历资源(例如,数据库行读取器).循环结束后,资源再次关闭.

但是,可能会发生呼叫者决定不完成枚举的情况.这使资源保持开放.

例:

IEnumerable<Foo> Bar ()
{
    using (var r = OpenResource()) {
        while (r.Read ()) {
            yield return r;
        }
    }
}

// OK - this closes the resource again
foreach (var foo in Bar()) {
    Console.WriteLine (foo);
}

// Not OK - resource stays open!
Console.WriteLine (Bar().First());
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?我可以轻松取消枚举,即告诉它跳过循环的其余部分,或者将其丢弃(将清理代码放入Dispose)?

我考虑过返回一个Func<Result, bool>如此用户可以让它返回,false如果他完成迭代.同样,也可以使用某种取消令牌.但这两种方法对我来说都很麻烦.

xan*_*tos 12

通常它是IEnumerator<>实现的IDisposable,如果你看一下你的定义,IEnumerator<>你会看到:

public interface IEnumerator<out T> : IDisposable, IEnumerator
Run Code Online (Sandbox Code Playgroud)

foreach正确的语句Dispose()IEnumerator<>从接收IEnumerable<>,因此:

IEnumerable<SomeClass> res = SomeQuery();

foreach (SomeClass sc in res)
{
    if (something)
        break;
}
Run Code Online (Sandbox Code Playgroud)

在离开foreach以任何方式(的break,一个例外,自然整理res),所述Dispose()IEnumerator<>应被调用.见https://msdn.microsoft.com/en-us/library/aa664754(v=vs.71).aspx为的是如何一个例子foreach是实现(A try... finally...用Dispose()里面的finally)

请注意,C#将生成using用于yield函数内部的"正确"代码.例如,请参阅:http://goo.gl/Igzmiz

public IEnumerable<Foo> Bar()
{
    using (var r = OpenResource()) 
    {
        while (r.Read ()) 
        {
            yield return new Foo();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

被转换为某种东西

void IDisposable.Dispose()
{
    int num = this.<>1__state;
    if (num == -3 || num == 1)
    {
        try
        {
        }
        finally
        {
            this.<>m__Finally1();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所述Dispose()的方法IEnumerator<>将调用m__Finally1,将方法(IDisposable)this.<r>5__1.Dispose();(其中,5__1r从返回OpenResource()).该m__Finally甚至被称为如果代码简单的"退出"的while (r.Read ()):

if (!this.<r>5__1.Read())
{
    this.<>m__Finally1();
Run Code Online (Sandbox Code Playgroud)

和/或如果有例外.

 catch
 {
     this.System.IDisposable.Dispose();
Run Code Online (Sandbox Code Playgroud)