LINQ中延时执行的Enumerable类方法成员

Enumerable的扩展方法采用线性流程,每个运算法会被线性执行。这种执行方法如果操作类似关系型数据库数据源,效率会非常低下,所以Queryable重新定义这些扩展方法,把LINQ表达式拆解为表达式树,提供程序就可以根据表达式树生成关系型数据库的查询语句,即SQL命令,然后进行相关操作。

每个查询运算符的执行行为不同,大致分为立即执行和延时执行。延时执行的运算符将在枚举元素的时候被执行。

Enumerable类位于程序集System.Core.dll中,System.Linq命名空间下,并且直接集成自System.Object,存在于3.5及以上的.NET框架中。Enumerable是静态类,不能实例化和被继承,其成员只有一组静态和扩展方法。

LINQ不仅能够查询实现IEnumerable或IQueryable的类型,也能查询实现IEnumerable接口的类型。关于Enumerable方法的详细说明,请参考MSDN  Enumerable 类

理解LINQ首先必须理解扩展方法

msdn是这样规定扩展方法的:“扩展方法被定义为静态方法,但它们是通过实例方法语法进行调用的。 它们的***个参数指定该方法作用于哪个类型,并且该参数以 this 修饰符为前缀。”

下面给个扩展方法的例子如下:

  
 
 
 
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Text; 
  5.  
  6. namespace 扩展方法 
  7. { 
  8.     ///  
  9.     /// 为string类型定义一个扩展方法 
  10.     ///  
  11.     static class Helper 
  12.     {  
  13.         public static string MyExtenMethod(this string s) 
  14.         { 
  15.             return s.Substring(0, 2); 
  16.         } 
  17.     } 
  18.     class Program 
  19.     { 
  20.         static void Main(string[] args) 
  21.         { 
  22.             string s = "扩展方法示例"; 
  23.             Console.WriteLine(s.MyExtenMethod());//调用 
  24.             Console.ReadKey(false); 
  25.         } 
  26.     } 
  27. } 

程序的运行结果如下:

 -----插曲,想到了就加进来,有助于理解开头的几段话及LINQ原理

 ---------------------------------------------------------------”

 为了方便理解和记忆,DebugLZQ将常用的延时执行的Enumerable类方法成员分了下组,具体如下:

1.Take用于从一个序列的开头返回指定数量的元素

2.TakeWhile 用于获取指定序列从头开始符合条件的元素,直到遇到不符合条件的元素为止

3.Skip跳过序列中指定数量的元素

4.SkipWhile 用于跳过序列总满足条件的元素,然会返回剩下的元素

  
 
 
 
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Text; 
  5.  
  6. namespace 延时执行的Enumerable类方法 
  7. { 
  8.     ///  
  9.     /// 延时执行的Enumerable类方法 
  10.     /// DebugLZQ 
  11.     /// http://www.cnblogs.com/DebugLZQ 
  12.     ///  
  13.     class Program 
  14.     { 
  15.         static void Main(string[] args) 
  16.         { 
  17.             string[] names = { "DebugLZQ","DebugMan","Sarah","Jerry","Tom","Linda","M&M","Jeffery"}; 
  18.             //1.Take用于从一个序列的开头返回指定数量的元素 
  19.             // 
  20.             //a.在数组上直接使用Take方法 
  21.             foreach (string name in names.Take(3)) 
  22.             { 
  23.                 Console.Write("{0}    ", name);  
  24.             } 
  25.             Console.WriteLine(); 
  26.             Console.WriteLine("-----"); 
  27.             //b.在LINQ返回的IEnumerable序列上使用Take方法 
  28.             var query = from string name in names 
  29.                         where name.Length <=3 
  30.                         select name; 
  31.             foreach (string  name in query.Take(1)) 
  32.             { 
  33.                 Console.Write("{0}    ",name); 
  34.             } 
  35.             Console.WriteLine(); 
  36.             Console.WriteLine("----------------------------"); 
  37.             Console.ReadKey(false); 
  38.             //2.TakeWhile 用于获取指定序列从头开始符合条件的元素,直到遇到不符合条件的元素为止 
  39.             // 
  40.             var takenames = names.TakeWhile(n => n.Length>4); 
  41.             var takenames2 = names.TakeWhile((n,i)=>n.Length<10&&i<3); 
  42.             foreach (string name in takenames) 
  43.             { 
  44.                 Console.Write("{0}    ", name); 
  45.             } 
  46.             Console.WriteLine(); 
  47.             Console.WriteLine("-----"); 
  48.             foreach (string name in takenames2) 
  49.             { 
  50.                 Console.Write("{0}    ", name); 
  51.             } 
  52.             Console.WriteLine(); 
  53.             Console.WriteLine("----------------------------"); 
  54.             Console.ReadKey(false); 
  55.             //3.Skip跳过序列中指定数量的元素 
  56.             // 
  57.             foreach (string name in names.Skip(5)) 
  58.             { 
  59.                 Console.Write("{0}    ", name); 
  60.             } 
  61.             Console.WriteLine(); 
  62.             Console.WriteLine("-----"); 
  63.             var query_skip = (from name in names 
  64.                               where name.Length >= 3 
  65.                               select name).Skip(2); 
  66.             foreach (string name in query_skip.Skip(2) ) 
  67.             { 
  68.                 Console.Write("{0}    ", name); 
  69.             } 
  70.             Console.WriteLine(); 
  71.             Console.WriteLine("----------------------------"); 
  72.             Console.ReadKey(false); 
  73.             //4.SkipWhile 用于跳过序列总满足条件的元素,然会返回剩下的元素 
  74.             //跳过名字长度大于3的 
  75.             var takenames_SkipWhile = names.SkipWhile(n => n.Length >3); 
  76.             foreach (string name in takenames_SkipWhile) 
  77.             { 
  78.                 Console.Write("{0}    ", name); 
  79.             } 
  80.             Console.WriteLine(); 
  81.             Console.WriteLine("-----"); 
  82.             var takenames_SkipWhile2 = names.SkipWhile((n,i)=>n.Length>3&&i>2); 
  83.             foreach (string name in takenames_SkipWhile2) 
  84.             { 
  85.                 Console.Write("{0}    ", name); 
  86.             } 
  87.             Console.WriteLine(); 
  88.             Console.WriteLine("----------------------------"); 
  89.             Console.ReadKey(false); 
  90.  
  91.             //小结Take、Skip获得第N到第M个元素 
  92.             var names_TakeAndSkip = names.Skip(5).Take(3); 
  93.  
  94.             var names_TakeAndSkip2 = (from name in names 
  95.                                       select name).Skip(5).Take(3); 
  96.  
  97.             foreach (string name in names_TakeAndSkip) 
  98.             { 
  99.                 Console.Write("{0}    ", name); 
  100.             } 
  101.             Console.WriteLine(); 
  102.             Console.WriteLine("-----"); 
  103.             foreach (string name in names_TakeAndSkip2) 
  104.             { 
  105.                 Console.Write("{0}    ", name); 
  106.             } 
  107.             Console.WriteLine(); 
  108.             Console.WriteLine("----------------------------"); 
  109.             Console.ReadKey(false); 
  110.  
  111.         } 
  112.     } 
  113. } 

程序中有详细的注释不再多做说明,程序运行结果如下:

5.Reverse用于翻转序列中的元素的顺序

6.Distinct过滤掉重复的元素

  
 
 
 
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Text; 
  5.  
  6. namespace Reverse_Distinct等 
  7. { 
  8.     ///  
  9.     /// DebugLZQ 
  10.     /// http://www.cnblogs.com/DebugLZQ 
  11.     ///  
  12.     class Program 
  13.     { 
  14.         static void Main(string[] args) 
  15.         { 
  16.             string[] names = { "DebugLZQ", "Jerry", "Sarah", "Jerry", "Tom", "Linda", "M&M", "Jeffery" }; 
  17.             //5.Reverse用于翻转序列中的元素的顺序 
  18.            string str = "反转字符串"; 
  19.  
  20.            var strre = str.ToCharArray().Reverse(); 
  21.            var takenames = names.Reverse(); 
  22.  
  23.            foreach (var c in strre) 
  24.            { 
  25.                Console.Write(c); 
  26.            } 
  27.            Console.WriteLine(); 
  28.            Console.WriteLine("-----"); 
  29.            foreach (var c in takenames ) 
  30.            { 
  31.                Console.WriteLine(c); 
  32.            } 
  33.            Console.WriteLine("----------------------------"); 
  34.            Console.ReadKey(false); 
  35.  
  36.             //6.Distinct  过滤掉重复的元素 
  37.            var takenames_Distinct = names.Distinct(); 
  38.  
  39.            foreach (var c in takenames_Distinct) 
  40.            { 
  41.                Console.WriteLine(c); 
  42.            } 
  43.            Console.WriteLine("----------------------------"); 
  44.            Console.ReadKey(false); 
  45.         } 
  46.     } 
  47. } 

程序的运行结果如下:

7.Union用于合并两个序列,并去掉重复项

8.Concat用于连接两个序列,不会去掉重复项

9.Intersect用于获得连个序列的交集

10.Except用于获得两个结合的差集

  
 
 
 
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Text; 
  5.  
  6. namespace Union_Concat_Intersect_Except 
  7. { 
  8.     ///  
  9.     /// DebugLZQ 
  10.     /// http://www.cnblogs.com/DebugLZQ 
  11.     ///  
  12.     class Program 
  13.     { 
  14.         static void Main(string[] args) 
  15.         { 
  16.             string[] names1 = { "DebugLZQ", "Jerry", "Sarah", "Jerry", "Tom", "Linda", "M&M", "Jeffery" }; 
  17.             string[] names2 = { "DebugLZQ", "Jerry", "Sarah" }; 
  18.  
  19.             //7.Union用于合并两个序列,并去掉重复项 
  20.             var names_Union = names1.Union(names2); 
  21.  
  22.             //8.Concat用于连接两个序列,不会去掉重复项 
  23.             var names_Concat = names1.Concat(names2); 
  24.  
  25.             //9.Intersect用于获得连个序列的交集 
  26.             var names_Intersect = names1.Intersect(names2); 
  27.  
  28.             //10.Except用于获得两个结合的差集 
  29.             var names_Except = names1.Except(names2); 
  30.  
  31.             foreach (string name in names_Union) 
  32.             { 
  33.                 Console.WriteLine(name); 
  34.             } 
  35.             Console.WriteLine("-----"); 
  36.             Console.ReadKey(false); 
  37.             foreach (string name in names_Concat) 
  38.             { 
  39.                 Console.WriteLine(name); 
  40.             } 
  41.             Console.WriteLine("-----"); 
  42.             Console.ReadKey(false); 
  43.             foreach (string name in names_Intersect) 
  44.             { 
  45.                 Console.WriteLine(name); 
  46.             } 
  47.             Console.WriteLine("-----"); 
  48.             Console.ReadKey(false); 
  49.             foreach (string name in names_Except) 
  50.             { 
  51.                 Console.WriteLine(name); 
  52.             } 
  53.             Console.WriteLine("-----"); 
  54.             Console.ReadKey(false); 
  55.         } 
  56.     } 
  57. } 

程序的运行结果如下:

11.Range 用于生成指定范围内的“整数”序列

12.Repeat用于生成指定数量的重复元素

13.Empty 用于获得一个指定类型的空序列

14.DefaultIfEmpty 用于获得序列,如果为空,则添加一个默认类型元素

  
 
 
 
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Text; 
  5.  
  6. namespace Range_Empty_DefalultIfEmpty 
  7. { 
  8.     ///  
  9.     /// DebugLZQ 
  10.     /// http://www.cnblogs.com/DebugLZQ 
  11.     ///  
  12.     class Program 
  13.     { 
  14.         static void Main(string[] args) 
  15.         { 
  16.             //11.Range 用于生成指定范围内的“整数”序列 
  17.             var num2 = Enumerable.Range(10, 15); 
  18.  
  19.             //12.Repeat用于生成指定数量的重复元素 
  20.             var guest = new {Name="橙子",Age=25 }; 
  21.             var Guests = Enumerable.Repeat(guest, 5); 
  22.  
  23.             //13.Empty 用于获得一个指定类型的空序列 
  24.             var empty = Enumerable.Empty(); 
  25.  
  26.             //14.DefaultIfEmpty 用于获得序列,如果为空,则添加一个默认类型元素 
  27.             //a 
  28.             var intempty = Enumerable.Empty(); 
  29.             Console.WriteLine(intempty.Count()); 
  30.             Console.WriteLine("-----------"); 
  31.             foreach (var n in intempty) 
  32.             { 
  33.                 Console.WriteLine(n);             
  34.             } 
  35.             Console.WriteLine("-----------"); 
  36.             Console.WriteLine(intempty.DefaultIfEmpty().Count()); 
  37.             Console.WriteLine("-----------"); 
  38.             foreach (var n in intempty.DefaultIfEmpty()) 
  39.             { 
  40.                 Console.WriteLine(n); 
  41.             } 
  42.             Console.WriteLine("--------------------------"); 
  43.             Console.ReadKey(false); 
  44.             //b 
  45.             string[] names = { "DebugLZQ", "DebugMan", "Sarah", "Jerry", "Tom", "Linda", "M&M", "Jeffery" }; 
  46.             var query = from name in names 
  47.                         where name == "LBJ" 
  48.                         select name; 
  49.             Console.WriteLine(query.Count()); 
  50.             Console.WriteLine(query.DefaultIfEmpty().Count());//默认为null 
  51.             foreach (var n in query.DefaultIfEmpty()) 
  52.             { 
  53.                 Console.WriteLine(n); 
  54.             } 
  55.             Console.WriteLine("---------------"); 
  56.             Console.ReadKey(false); 
  57.             //c指定一个默认值 
  58.             foreach (var n in intempty.DefaultIfEmpty(100)) 
  59.             { 
  60.                 Console.WriteLine(n); 
  61.             } 
  62.             Console.WriteLine("--------------------------"); 
  63.             Console.ReadKey(false); 
  64.  
  65.             foreach (var n in query.DefaultIfEmpty("James")) 
  66.             { 
  67.                 Console.WriteLine(n); 
  68.             } 
  69.             Console.ReadKey(false); 
  70.         } 
  71.     } 
  72. } 

程序的运行结果如下:

15.OfType筛选指定类型的元素

16.Cast类型转换

17.AsEnumerable有些数据源类型不支持Enumerable的部分查询关键字,需要转换下,譬如IQueryable

  
 
 
 
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Text; 
  5. using System.Collections; 
  6.  
  7. namespace Cast_OfType_AsEnumerable 
  8. { 
  9.     ///  
  10.     /// DebugLZQ 
  11.     /// http://www.cnblogs.com/DebugLZQ 
  12.     ///  
  13.     class Program 
  14.     { 
  15.         static void Main(string[] args) 
  16.         { 
  17.             ArrayList names = new ArrayList(); 
  18.             names.Add("DebugLZQ"); 
  19.             names.Add("Jerry"); 
  20.             names.Add(100); 
  21.             names.Add(new {Name="LZQ",Age=26}); 
  22.             names.Add(new Stack()); 
  23.             //15.OfType筛选指定类型的元素 
  24.             var takenames = names.OfType(); 
  25.  
  26.             //16.Cast类型转换 
  27.             var takenames2 = names.OfType().Cast(); 
  28.  
  29.             //17.AsEnumerable 
  30.             var takenames3 = takenames2.AsEnumerable(); 
  31.  
  32.             foreach (var name in takenames3) 
  33.             { 
  34.                 Console.Write("{0}  ",name); 
  35.             } 
  36.             Console.ReadKey(false); 
  37.  
  38.         } 
  39.     } 
  40. } 

程序运行结果如下:

 延时执行,顾名思义就是不是立即执行,即不是在查询语句定义的时候执行,而是在处理结果集(如遍历)的时候执行,在Enumerable类方法成员中,除了本节总结的这常用的17个外,前面博文---LINQ基本子句 中总结的8个基本子句也都是延时执行的。注意延时执行的查询程序的执行流程。


网站题目:LINQ中延时执行的Enumerable类方法成员
分享链接:http://wkslyf.com/article/cccchhj.html