web-dev-qa-db-ja.com

使用するIEnumerable <T>を破棄することを検討する必要がありますか?

最近、さまざまなLinq拡張メソッド(WhereSelectなど)がIEnumerable<T>を返すことが指摘されましたが、これはたまたまIDisposableでもあります。以下はTrueに評価されます

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

Where式の結果を破棄する必要がありますか?

IEnumerable<T>を返すメソッドを呼び出すたびに、処理を終えたときにdisposeを呼び出す責任を(潜在的に)受け入れますか?

69
Rob

いいえ、これについて心配する必要はありません。

それらがIDisposable実装を返すという事実は実装の詳細です。C#コンパイラのMicrosoft実装のイテレータブロックは、IEnumerable<T>IEnumerator<T>の両方を実装するsingleタイプを作成するためです。後者は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;
    }
}

doは、IEnumerator<T>IDisposableを実装するという事実に注意する必要があることに注意してください。したがって、明示的に反復するときはいつでも、適切に廃棄する必要があります。たとえば、何かを反復処理し、常にa値を使用するようにしたい場合は、次のようなものを使用できます。

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
    }
}

(もちろん、foreachループがこれを自動的に行います。)

81
Jon Skeet