Přechodná materializace (C#)
Pokud nejste opatrní, můžete v některých situacích výrazně změnit profil paměti a výkonu vaší aplikace tím, že způsobí předčasné materializaci kolekcí v dotazech. Některé standardní operátory dotazů způsobují materializaci své zdrojové kolekce před předáním jednoho prvku. Například Enumerable.OrderBy nejprve iteruje celou zdrojovou kolekci, pak seřadí všechny položky a nakonec získá první položku. To znamená, že je nákladné získat první položku seřazené kolekce; poté není každá položka nákladná. To dává smysl; Operátor dotazu by nebylo možné provést jinak.
Příklad: Přidání metody, která volá ToList
, což způsobuje materializaci
Tento příklad změní příklad v příkladu řetězových dotazů (C#):AppendString
Metoda se změní tak, aby volala ToList před iterací prostřednictvím zdroje, což způsobuje materializaci.
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();
}
}
}
Tento příklad vytvoří následující výstup:
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!!!<
V tomto příkladu vidíte, že volání ToList způsobí AppendString
vytvoření výčtu celého zdroje před uvedením první položky. Pokud by byl zdroj velkým polem, výrazně by se změnil profil paměti aplikace.
Standardní operátory dotazů lze také zřetědět, jak je znázorněno v posledním článku v tomto kurzu: