LINQ学习笔记:查询是怎么执行的
延迟执行 对于多数的查询操作符来说, 他们并不是在构造后被立即执行, 而是当枚举发生的时候, 换句话说就是当它对应的枚举器上的MoveNext被调用的时候. 例如下面的查询: 1: var numbers = new List<int>( ); 2: numbers.Add (3);
3:
4: IEnumerable<int> q = numbers.Select (n => n + 2); 5: numbers.Add (5);
6:
7: foreach (int n in q) 8: Console.Write (n + ","); //5,7,
可以发现我们在查询构造之后插入的数字也包含在结果之中, 因为只有当foreach表达式运行的时候过滤或者排序才会发生. 我们把它称为延迟执行. 几乎所有的标准查询操作符都具有延迟执行的能力, 但以下这些是例外: 1. 那些返回单一元素或者单一值得操作符, 例如First或者Count 2. 转换操作符: ToArray, ToList, ToDictionary, ToLookup 这些操作符会被立即执行因为他们的返回类型没有任何的机制来提供延迟执行. 例如Count, 返回一个简单的整数类型, 没有办法被枚举. 例如下面的查询会被立即执行: 1: int result = numbers.Where (n => n <6).Count(); 2: Console.WriteLine(result); //2
延迟执行非常重要是因为它将查询构造和执行解耦了. 这允许你可以分几步构造一个查询, 并使LINQ to SQL变得可能. 重估值 延迟执行还带来另外一个后果, 就是当你重新枚举的时候延迟执行的查询将会被重新计算. 1: var numbers = new List<int>( ) { 5, 6 }; 2:
3: IEnumerable<int> q = numbers.Select (n => n + 10); 4: foreach (int n in q) 5: Console.Write (n + ","); // 15,16, 6:
7: numbers.Clear( );
8: foreach (int n in q) 9: Console.Write (n + ","); // nothing
有几个理由可以解释为什么重估有些时候会带来一些不利的影响: 1. 有些时候你想在一个特定的点及时冻结或者缓存结果 2. 有些查询是密集计算(或者依赖于一个远程数据库), 因此我们不想做一些不必要的重复. 要避免重估我们可以调用一个转换操作符, 例如ToArray或者ToList. ToArray将一个输出序列拷贝到一个数组, ToList则是将其拷贝到一个泛型的List<>: 1: var numbers = new List<int>( ) { 5, 6, 7 }; 2:
3: List<int> r = numbers 4: .Select (n => n + 10)
5: .ToList( );
6:
7: numbers.Clear( );
8: Console.WriteLine (r.Count); //3
|
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |