web-dev-qa-db-fra.com

Dois-je envisager de supprimer tout IEnumerable <T> que j'utilise?

On m'a récemment fait remarquer que diverses méthodes d'extension Linq (telles que Where, Select, etc.) renvoient un IEnumerable<T> qui se trouve être également IDisposable. Ce qui suit correspond à True

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

Dois-je supprimer les résultats d'une expression Where?

Chaque fois que j'appelle une méthode renvoyant IEnumerable<T>, est-ce que j'accepte (potentiellement) la responsabilité d'appeler disposer lorsque j'en ai fini?

69
Rob

Non, vous n'avez pas à vous en préoccuper.

Le fait qu'ils retournent une implémentation IDisposable est un détail d'implémentation - c'est parce que les blocs d'itérateur dans l'implémentation Microsoft du compilateur C # créent un type nique qui implémente les deux IEnumerable<T> et IEnumerator<T>. Ce dernier étend IDisposable, c'est pourquoi vous le voyez.

Exemple de code pour le démontrer:

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

Notez que vous faites devez prendre note du fait que IEnumerator<T> implémente IDisposable. Donc, chaque fois que vous répétez explicitement, vous devez vous en débarrasser correctement. Par exemple, si vous voulez parcourir quelque chose et être sûr que vous aurez toujours la valeur a, vous pouvez utiliser quelque chose comme:

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

(Une boucle foreach le fera automatiquement, bien sûr.)

81
Jon Skeet