Должен ли я рассмотреть возможность утилизации любого IEnumerable <T>, который я использую?

Недавно мне сообщили, что различные методы расширения Linq (такие как Where, Select и т.д.) возвращают IEnumerable<T>, который также оказывается IDisposable. Нижеследующее оценивается как True

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

Нужно ли мне удалять результаты выражения Where?

Всякий раз, когда я вызываю метод, возвращающий IEnumerable<T>, могу ли я (потенциально) принять ответственность за вызов, когда я закончил с ним?

Ответ 1

Нет, вам не нужно беспокоиться об этом.

Тот факт, что они возвращают реализацию IDisposable, представляет собой деталь реализации - это потому, что блоки iterator в реализации Microsoft компилятора С# создают один тип, который реализует как 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;
    }
}

Обратите внимание, что вам нужно обратить внимание на то, что 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
    }
}

foreach цикл сделает это автоматически, конечно.)