延时执行的Enumerable类方法
LINQ标准查询运算法是依靠一组扩展方法来实现的。而这些扩展方法分别在System.Linq.Enumerable和System.Linq.Queryable这连个静态类中定义。
Enumerable的扩展方法采用线性流程,每个运算法会被线性执行。这种执行方法如果操作类似关系型数据库数据源,效率会非常低下,所以Queryable重新定义这些扩展方法,把LINQ表达式拆解为表达式树,提供程序就可以根据表达式树生成关系型数据库的查询语句,即SQL命令,然后进行相关操作。
每个查询运算符的执行行为不同,大致分为立即执行和延时执行。延时执行的运算符将在枚举元素的时候被执行。
Enumerable类位于程序集System.Core.dll中,System.Linq命名空间下,并且直接集成自System.Object,存在于3.5及以上的.NET框架中。Enumerable是静态类,不能实例化和被继承,其成员只有一组静态和扩展方法。
LINQ不仅能够查询实现IEnumerable<T>或IQueryable<T>的类型,也能查询实现IEnumerable接口的类型。
理解LINQ首先必须理解扩展方法
msdn是这样规定扩展方法的:“扩展方法被定义为静态方法,但它们是通过实例方法语法进行调用的。 它们的第一个参数指定该方法作用于哪个类型,并且该参数以 this 修饰符为前缀。”
下面给个扩展方法的例子如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 扩展方法 { /// <summary> /// 为string类型定义一个扩展方法 /// </summary> static class Helper { public static string MyExtenMethod(this string s) { return s.Substring(0, 2); } } class Program { static void Main(string[] args) { string s = "扩展方法示例"; Console.WriteLine(s.MyExtenMethod());//调用 Console.ReadKey(false); } } }</div>
程序的运行结果如下:
为了方便理解和记忆,将常用的延时执行的Enumerable类方法成员分了下组,具体如下:
1.Take用于从一个序列的开头返回指定数量的元素
2.TakeWhile 用于获取指定序列从头开始符合条件的元素,直到遇到不符合条件的元素为止
3.Skip跳过序列中指定数量的元素
4.SkipWhile 用于跳过序列总满足条件的元素,然会返回剩下的元素
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 延时执行的Enumerable类方法 { class Program { static void Main(string[] args) { string[] names = { "DebugLZQ","DebugMan","Sarah","Jerry","Tom","Linda","M&M","Jeffery"}; //1.Take用于从一个序列的开头返回指定数量的元素 // //a.在数组上直接使用Take方法 foreach (string name in names.Take(3)) { Console.Write("{0} ", name); } Console.WriteLine(); Console.WriteLine("-----"); //b.在LINQ返回的IEnumerable<T>序列上使用Take方法 var query = from string name in names where name.Length <=3 select name; foreach (string name in query.Take(1)) { Console.Write("{0} ",name); } Console.WriteLine(); Console.WriteLine("----------------------------"); Console.ReadKey(false); //2.TakeWhile 用于获取指定序列从头开始符合条件的元素,直到遇到不符合条件的元素为止 // var takenames = names.TakeWhile(n => n.Length>4); var takenames2 = names.TakeWhile((n,i)=>n.Length<10&&i<3); foreach (string name in takenames) { Console.Write("{0} ", name); } Console.WriteLine(); Console.WriteLine("-----"); foreach (string name in takenames2) { Console.Write("{0} ", name); } Console.WriteLine(); Console.WriteLine("----------------------------"); Console.ReadKey(false); //3.Skip跳过序列中指定数量的元素 // foreach (string name in names.Skip(5)) { Console.Write("{0} ", name); } Console.WriteLine(); Console.WriteLine("-----"); var query_skip = (from name in names where name.Length >= 3 select name).Skip(2); foreach (string name in query_skip.Skip(2) ) { Console.Write("{0} ", name); } Console.WriteLine(); Console.WriteLine("----------------------------"); Console.ReadKey(false); //4.SkipWhile 用于跳过序列总满足条件的元素,然会返回剩下的元素 //跳过名字长度大于3的 var takenames_SkipWhile = names.SkipWhile(n => n.Length >3); foreach (string name in takenames_SkipWhile) { Console.Write("{0} ", name); } Console.WriteLine(); Console.WriteLine("-----"); var takenames_SkipWhile2 = names.SkipWhile((n,i)=>n.Length>3&&i>2); foreach (string name in takenames_SkipWhile2) { Console.Write("{0} ", name); } Console.WriteLine(); Console.WriteLine("----------------------------"); Console.ReadKey(false); //小结Take、Skip获得第N到第M个元素 var names_TakeAndSkip = names.Skip(5).Take(3); var names_TakeAndSkip2 = (from name in names select name).Skip(5).Take(3); foreach (string name in names_TakeAndSkip) { Console.Write("{0} ", name); } Console.WriteLine(); Console.WriteLine("-----"); foreach (string name in names_TakeAndSkip2) { Console.Write("{0} ", name); } Console.WriteLine(); Console.WriteLine("----------------------------"); Console.ReadKey(false); } } }</div>
程序中有详细的注释不再多做说明,程序运行结果如下:
5.Reverse用于翻转序列中的元素的顺序
6.Distinct过滤掉重复的元素
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Reverse_Distinct等 { class Program { static void Main(string[] args) { string[] names = { "DebugLZQ", "Jerry", "Sarah", "Jerry", "Tom", "Linda", "M&M", "Jeffery" }; //5.Reverse用于翻转序列中的元素的顺序 string str = "反转字符串"; var strre = str.ToCharArray().Reverse(); var takenames = names.Reverse(); foreach (var c in strre) { Console.Write(c); } Console.WriteLine(); Console.WriteLine("-----"); foreach (var c in takenames ) { Console.WriteLine(c); } Console.WriteLine("----------------------------"); Console.ReadKey(false); //6.Distinct 过滤掉重复的元素 var takenames_Distinct = names.Distinct(); foreach (var c in takenames_Distinct) { Console.WriteLine(c); } Console.WriteLine("----------------------------"); Console.ReadKey(false); } } }</div>
程序的运行结果如下:
7.Union用于合并两个序列,并去掉重复项
8.Concat用于连接两个序列,不会去掉重复项
9.Intersect用于获得连个序列的交集
10.Except用于获得两个结合的差集
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Union_Concat_Intersect_Except { /// <summary> /// DebugLZQ /// http://www.cnblogs.com/DebugLZQ /// </summary> class Program { static void Main(string[] args) { string[] names1 = { "DebugLZQ", "Jerry", "Sarah", "Jerry", "Tom", "Linda", "M&M", "Jeffery" }; string[] names2 = {