Partager via


Matérialisation intermédiaire

Si vous n'y prenez pas garde, dans certaines situations vous risquez de modifier de manière significative le profil de mémoire et de performances de votre application en provoquant la matérialisation prématurée de collections dans vos requêtes. Certains opérateurs de requête standard provoquent la matérialisation de leur collection source avant de générer un seul élément. Par exemple, Enumerable.OrderBy itère au sein de l'ensemble de sa collection source, trie tous les éléments, puis génère le premier élément. Cela signifie qu'il est coûteux d'obtenir le premier élément d'une collection ordonnée ; chaque élément ultérieur a un faible coût. Tout cela est logique : il serait impossible pour cet opérateur de requête de faire autrement.

Exemple

Cet exemple modifie l'exemple précédent . La méthode AppendString appelle ToList<TSource> avant d'itérer la source. Cela provoque la matérialisation.

Notes

L'exemple suivant utilise la construction yield return de C#. Étant donné qu'il n'y a aucune fonctionnalité équivalente en Visual Basic 2008, cet exemple est fourni uniquement en C#.

public static class LocalExtensions
{
    public static IEnumerable<string>
      ConvertCollectionToUpperCase(this IEnumerable<string> source)
    {
        foreach (string str in source)
        {
            Console.WriteLine("ToUpper: source >{0}<", str);
            yield return str.ToUpper();
        }
    }

    public static IEnumerable<string>
      AppendString(this IEnumerable<string> source, string stringToAppend)
    {
        // the following statement materializes the source collection in a List<T>
        // before iterating through it
        foreach (string str in source.ToList())
        {
            Console.WriteLine("AppendString: source >{0}<", str);
            yield return str + stringToAppend;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        string[] stringArray = { "abc", "def", "ghi" };

        IEnumerable<string> q1 =
            from s in stringArray.ConvertCollectionToUpperCase()
            select s;

        IEnumerable<string> q2 =
            from s in q1.AppendString("!!!")
            select s;

        foreach (string str in q2)
        {
            Console.WriteLine("Main: str >{0}<", str);
            Console.WriteLine();
        }
    }
}

Cet exemple produit la sortie suivante :

ToUpper: source >abc<
ToUpper: source >def<
ToUpper: source >ghi<
AppendString: source >ABC<
Main: str >ABC!!!<

AppendString: source >DEF<
Main: str >DEF!!!<

AppendString: source >GHI<
Main: str >GHI!!!<

Dans cet exemple, on observe que l'appel de ToList<TSource> force AppendString à parcourir l'ensemble de sa source avant de générer le premier élément. Si la source est un grand tableau, cela modifie considérablement le profil de mémoire de l'application.

Étapes suivantes

Les opérateurs de requête standard peuvent également être chaînés ensemble. La dernière rubrique de ce didacticiel illustre cela.

Voir aussi

Concepts

Didacticiel : Chaînage de requêtes