Compartir por


Materialización intermedia (C#)

Si no tiene cuidado, en algunas situaciones puede alterar drásticamente el perfil de memoria y rendimiento de la aplicación y causar una materialización prematura de recopilaciones en las consultas. Algunos operadores de consulta estándar provocan la materialización de su colección de origen antes de producir un solo elemento. Por ejemplo, Enumerable.OrderBy primero recorre en iteración toda su colección de origen, ordena todos los elementos y, por último, produce el primer elemento. Esto significa que es costoso obtener el primer elemento de una colección ordenada; cada elemento a partir de entonces no es caro. Esto tiene sentido; sería imposible que ese operador de consulta hiciera lo contrario.

Ejemplo: Agregar un método que llama a ToList, lo que provoca la materialización

En este ejemplo se modifica el ejemplo de Ejemplo de consultas de cadena (C#): el método AppendString se cambia para llamar a ToList antes de iterar por el origen, lo que provoca la materialización.

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

En este ejemplo se genera la siguiente salida:

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

En este ejemplo, puede ver que la llamada a ToList hace AppendString que enumere todo su origen antes de producir el primer elemento. Si el origen fuera una matriz grande, esto modificaría significativamente el perfil de memoria de la aplicación.

Los operadores de consulta estándar también se pueden encadenar como se muestra en el artículo final de este tutorial:

Consulte también