LINQ中的"延迟查询"特性

        很多标准查询操作符的设计原型都是返回一个IEnumerable<T>类型的序列, 这些标准查询操作实际上不会在代码执行到那一行的时候就返回一个序列, 事实上返回的是一个对象. 当在枚举(比如foreach)这个对象的时候会从IEnumerable<T>序列中生成一个元素, 这个时候才会真正执行查询操作. 这就是所谓的"延迟查询".

小例子证明"延迟查询"的存在性

int[] intArray = new int[] { 0, 1, 2, 3 };
IEnumerable<int> items = intArray.Select(i => i); //返回i
//输出结果
foreach (int item in items)
    Console.WriteLine(item);
//更改一下intArray中的某个元素, 再进行"输出结果"
intArray[0] = 4;
Console.WriteLine("改变intArray第一个元素值之后的输出结果:");
//再次输出结果
foreach (int item in items)
    Console.WriteLine(item);

        两次输出结果分别为:0, 1, 2, 3 和 4, 1, 2, 3. 由此可见只有在枚举items的时候才会真正的执行查询操作. 如果没有延迟查询, 两次输出的结果应该是相同的.

避免"延迟查询"的方法

        可以使用一个不返回IEnumerable<T>数据类型的转换操作符, 如ToArray, ToList, ToDictionary或ToLookup, 这样查询操作就不会被延迟了. 同样是上面例子的, 通过ToList操作符返回一个List<int>型序列, 就不会产生"延迟查询"的现象:

int[] intArray = new int[] { 0, 1, 2, 3 };
List<int> items = intArray.Select(i => i).ToList(); //加了ToList操作符
//输出结果
foreach (int item in items)
    Console.WriteLine(item);
//更改一下intArray中的某个元素, 再进行"输出结果"
intArray[0] = 4;
Console.WriteLine("改变intArray第一个元素值之后的输出结果:");
//再次输出结果
foreach (int item in items)
    Console.WriteLine(item);

        这样两次输出的结果就都为0, 1, 2, 3了.

"延迟查询"可能导致的错误

        因为有了延迟, 被枚举的时候才会真正的去执行一个查询, 因此如果程序编译通过了但绝对不意味着这个查询就是没事儿的. 比如查询一个字符串数组里面, 每个元素的第3个字符是什么的时候, 如果某个字符串长度<3, 那么在运行的时候就会报错, 而程序在编译的时候是没有问题的.

posted @ 2011-02-23 11:44  Create Chen  阅读(2026)  评论(3编辑  收藏  举报