如果您不小心,可能會在某些情況下,由於在查詢中導致集合過早具像化而大幅改變應用程式的記憶體和效能表現。 某些標準查詢運算符在產生單一元素之前,會導致其來源集合具體化。 例如, Enumerable.OrderBy 先逐一查看其整個來源集合,然後排序所有專案,最後產生第一個專案。 這表示要取得已排序集合的第一個項目會很昂貴;而此後的每個項目則不昂貴。 這很合理:否則,該查詢運算符不可能這麼做。
範例:新增一個會呼叫ToList的方法,進而引起具象化。
此範例修改了 Chain 查詢範例 (C#) 中的範例:AppendString 方法會在逐一查看來源之前改為呼叫 ToList,這會導致資料的具象化。
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();
}
}
}
此範例會產生下列輸出:
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!!!<
在此範例中,您可以看到 呼叫 ToList 會導致 AppendString 在產生第一個專案之前列舉其整個來源。 如果來源是大型陣列,這會大幅改變應用程式的記憶體狀況。
標準查詢運算子也可以鏈結在一起,如本教學課程的最後一篇文章所示: