问题描述
本文的目的是帮助大家搞清楚C#3.0里面的Linq查询表达式的来龙去脉,搞清楚以后对C#3.0的新特性基本上也就了然于胸了。建议大家看完Linq查询后再看各个语法新特性对Linq的意义,这样会更加有帮助一些。1、自动属性。classClass{//C#2.0属性//privateint_id;//publicintID//{//get{//return_id;//}//set//{//_id=value;//}//}//C#3.0属性可以给getset加访问修饰符publicintID{get;privateset;}publicstringName{get;set;}publicClass(intid){//加了private之后的属性只能在类的内部访问this.ID=id;}}本质:和原来的属性没啥两样,简化了语法而已。对Linq的意义:无。2、初始化器。privatestaticvoidInitializer(){//C#2.0对象初始化//Classc=newClass(1);//c.Name="终极一班";//C#3.0对象初始化器Classc=newClass(1){Name="终极一班"};//C#2.0集合初始化//ClassCollectionlist=newClassCollection();//list.Add(c);//C#3.0集合初始化器ClassCollectionlist=newClassCollection{newClass(1){Name="终极一班"},newClass(2){Name="终极二班"}};foreach(Classiteminlist){Console.WriteLine(item.ID+""+item.Name);}}相关的班级集合类代码:classClassCollection:List<Class>{}本质:和原来的构造函数初始化或构造后通过属性初始化没啥两样,简化了语法而已。对Linq的意义:和匿名类型结合起来构造查询结果集合里面的新元素类型。4、具有隐式类型的局部变量privatestaticvoidVar(){vari=1;//编译过后的结果实际是inti=1;var并不是动态变量,它的类型实际上是c#编译器通过上下文推断是int//vari=DateTime.Now;//编译不过,和JavaScript不一样vard=DateTime.Now;//=后面支持各种类型vara=newint[]{1,2,3};//var也支持数组foreach(varitemina)//item的类型通过C#编译器推断得知是int{Console.WriteLine(i);}//varx;//错误,没有用来推断类型的初始化器//vary={1,2,3};//错误,不允许使用集合初始化器//varz=null;//错误,不允许出现空类型}本质:var并非动态类型,C#仍然是静态语言,引入var方便我们写代码了,可以不管“=”后面的赋值表达式类型了,由编译器自己去推断生成对应类型了。对Linq的意义:可以自动推断出Linq查询返回的集合类型。5、匿名类型。privatestaticvoidAnonymousType(){varv=new{Name="张三",Sex=true};//无须显示声明一个类,而且在初始化器里面可以获取上下文的变量——闭包Console.WriteLine(v.Name);}本质:有了匿名类型后我们不需要显示的声明一个类型了,这个类型由C#编译器自动生成,而且利用了初始化器和var的新特性对Linq的意义:和初始化器结合起来构造查询结果集合里面的新元素类型。6、扩展方法。比如我们现在想给int类型增加(扩展)一个方法,判断一个整数自身是否偶数,我们期望的语法是这样的:privatestaticvoidExtendMethod(){inti=2;Console.WriteLine(i.IsEven());}注意原来int原来是没有IsEven()这个方法的,要实现这个方法,必须写一个静态类和一个静态方法。staticclassMyExtention{publicstaticboolIsEven(thisintnum)//this表示针对int的实例和索引器的this的含义是一样的,int表示给int这种类型进行扩展{returnnum%2==0;}}本质:编译i.IsEven()的本质是C#编译器生成了了MyExtention.IsEven(i)的代码,实际上仍然没有破坏类型的结构,并不是真的象语法那样平白无故给int增加了一个IsEven()方法,和设计模式里面的Visitor模式动态注入方法还是有区别的。对Linq的意义:用来对集合类型扩展不同的查询方法。7、Lambda表达式和Linq查询。接下来我们通过一个例子来看一下Lambda表达式和Linq查询的关系:我们现在想给ClassCollection增加一个过滤方法,方法的目的是能够过滤返回班级名称为“终极一班”的集合来。0)首先给MyExtention增加这么一个静态方法:publicstaticClassCollectionFilter(thisClassCollectionclasses){varnewlist=newClassCollection();foreach(variteminclasses){if(item.Name=="终极一班"){newlist.Add(item);}}returnnewlist;}privatestaticvoidLambdaLinq(){varclasses=GetClasses();//varstudents=GetStudents();//0原始版本varresult=classes.Filter();foreach(variteminresult){Console.WriteLine(item.ID+""+item.Name);}}相关的工厂方法:staticClassCollectionGetClasses(){returnnewClassCollection{newClass(1){Name="终极一班"},newClass(2){Name="终极二班"},};}1)现在需求发生了变化,需要上面的红色部分需要发生变化,也就是说我们希望这个查询条件可以在我们调用Filter方法的时候动态的指定,这时候我们可以把这个变化封装成一个接口,当然还可以封装成一个委托,这是.net的非常好用的独有特性,委托的最直接的作用可以把一个具体的方法引用封装成一个变量传递。好,开始变形!delegateboolFilterHandler(Classc);//注意这个要放到namespace下面,不要放到Program类里面publicstaticClassCollectionFilter(thisClassCollectionclasses,FilterHandlerf){varnewlist=newClassCollection();foreach(variteminclasses){if(f(item)){newlist.Add(item);}}returnnewlist;}staticboolF(Classc){returnc.Name=="终极一班";}privatestaticvoidLambdaLinq(){varclasses=GetClasses();//C#1.0使用委托封装过滤条件FilterHandlerf=newFilterHandler(F);varresult=classes.Filter(f);foreach(variteminresult){Console.WriteLine(item.ID+""+item.Name);}}我们声明了一个委托FilterHandler,只要满足这个委托的方法我们都可以传递给Filter方法,这样就实现了动态的改变查询条件的目的,F方法内部可以是任意的查询条件比如returnc.Name!="终极一班";同时我们不需要改变Filter方法内部稳定的部分。2)c#2.0里面也支持直接把一个方法传给一个委托,但本质上也是编译器把方法转换成了一个委托,例如上面:privatestaticvoidLambdaLinq(){varclasses=GetClasses();//C#2.0直接传递方法varresult=classes.Filter(F);foreach(variteminresult){Console.WriteLine(item.ID+""+item.Name);}}3)C#2.0里面有个新特性,叫匿名方法,我们可以直接传递匿名方法:privatestaticvoidLambdaLinq(){varclasses=GetClasses();//C#2.0传递匿名方法varresult=classes.Filter(delegate(Classc){returnc.Name=="终极一班";});foreach(variteminresult){Console.WriteLine(item.ID+""+item.Name);}}好,变形到这里,我们发现这个匿名其实不仅仅可以给我们带来不用给方法命名的好处,在这个方法内部我们还可以使用外部上下文环境的变量成员,这个特性也叫“闭包(Closure)”,JavaScript也支持这个特性,比如:privatestaticvoidLambdaLinq(){varclasses=GetClasses();stringclassName="终极一班";//C#2.0传递匿名方法varresult=classes.Filter(delegate(Classc){returnc.Name==className;});foreach(variteminresult){Console.WriteLine(item.ID+""+item.Name);}}
解决方案
解决方案二:
4)大家发现没有,上面的语法还是有点拖沓,伟大的Microsoft又给我们提供了一种更简洁的写法(我怎么说了个“又”呢?^_^),这也就是我们所说的Lambda表达式了:privatestaticvoidLambdaLinq(){varclasses=GetClasses();stringclassName="终极一班";//4C#3.0Lambda表达式varresult=classes.Filter(c=>c.Name==className);foreach(variteminresult){Console.WriteLine(item.ID+""+item.Name);}}“=>”左边的就是我们上面匿名方法的参数列表,右边的是方法里,实际上lambda表达式也可以写成如下形式:Classc=>c.Name==className(Classc)=>c.Name==className(Classc)=>{returnc.Name==className;}(x,y)=>x+y;//多参数等等,函数的返回类型也是由编译器根据"=>"右边的表达式自动推断出来的。而且需要提到的是由于Filter是扩展方法的缘故,而且Filter方法返回类型是ClassCollection,所以可以无限扩展下去,例如varresult=classes.Filter(c=>c.Name==className).Filter(c=>c.ID>1);这就是扩展方法的魅力所在!5)实际上不知不觉,我们已经实现了Linq里面的一个Where功能了我们现在导入命名空间usingSystem.Linq;然后会发现classes这个实例会增加了很多扩展方法例如Where,OrderBy,这些方法实际上就是一些给实现了IEnumerable接口的类型的扩展方法,说白了就是针对集合类型的一些相关方法,比如过滤、排序、合并、分组等方法,这些方法的返回类型依然是IEnumerable(大家可以把光标移动到Where方法上,然后调用“转到定义”去看看这些方法的定义就明白了)当然这些方法都离不开我们的Lambda表达式做参数。privatestaticvoidLambdaLinq(){varclasses=GetClasses();stringclassName="终极一班";//5C#3.0里面的Where扩展方法(专门给实现了IEnumerable接口的类做扩展)varresult=classes.Where(c=>c.Name==className);foreach(variteminresult){Console.WriteLine(item.ID+""+item.Name);}}我们还可以这样可以无限扩展下去:varresult=classes.Where(c=>c.Name==className).OrderBy(c=>c.ID);6)这样写针对IEnumarable类型的查询其实已经不错了,微软觉得还不过瘾,又提供了我们传说中的Linq查询表达式(又是“又”?!)privatestaticvoidLambdaLinq(){varclasses=GetClasses();stringclassName="终极一班";//6Linq查询表达式varresult=fromcinclasseswherec.Name==classNameorderbyc.IDselectc;foreach(variteminresult){Console.WriteLine(item.ID+""+item.Name);}}到这时候你还认识原来的扩展方法吗?所以说语言的抽象确实很好用,和人的思维很接近,但是我们还是要看到它的本质,其实它的本质都是面向对象的一些东西,并没有创造出一些什么新的东西来,这样我们才可以真正理解语言。7)最后一个稍微复杂一些的Linq查询,就是班级和学生结合的一个连接,连接的条件是班级的id和学生的所属班级id,然后生成一个新的集合,这个集合里面的元素成员包括班级名称和学生名称。涉及到的相关类如下:classStudent{publicintID{get;set;}publicstringName{get;set;}publicintClassID{get;set;}}classStudentCollection:List<Student>{}获取学生集合的工厂方法:staticStudentCollectionGetStudents(){returnnewStudentCollection(){newStudent{ID=1,Name="大东",ClassID=1},newStudent{ID=2,Name="亚瑟",ClassID=1},newStudent{ID=3,Name="小雨",ClassID=1},newStudent{ID=4,Name="雷克斯",ClassID=1},newStudent{ID=2,Name="张三",ClassID=2},newStudent{ID=3,Name="李四",ClassID=2},newStudent{ID=4,Name="王二麻子",ClassID=2}};}privatestaticvoidLambdaLinq(){varclasses=GetClasses();varstudents=GetStudents();//7Linq查询表达式Joinvarresult=fromcinclassesjoinsinstudentsonc.IDequalss.ClassIDselectnew{ClassName=c.Name,StudentName=s.Name};//匿名类型和初始化器新特性的使用//varresult=classes.Join(students,c=>c.ID,s=>s.ClassID,(c,s)=>new{ClassName=c.Name,StudentName=s.Name}foreach(variteminresult){Console.WriteLine(item.ClassName+""+item.StudentName);//注意元素的属性成员已经改变}}转自:http://blog.csdn.net/tongdoudpj/archive/2007/12/16/1942367.aspxhttp://www.cnblogs.com/szzhouke/archive/2007/12/16/996596.html
解决方案三:
//C#3.0集合初始化器ClassCollectionlist=newClassCollection{newClass(1){Name="终极一班"},newClass(2){Name="终极二班"}};foreach(Classiteminlist){Console.WriteLine(item.ID+""+item.Name);}在这个list里添加项目用的是newClass()?
解决方案四:
Linq的本质=语法糖(自动属性)+语法糖(初始化器)+语法糖(具有隐式类型的局部变量)+语法糖(匿名类型)+语法糖(扩展方法)+语法糖(更强的类型自动推断)+语法糖(Lambda表达式)+语法糖(编译为Lambda表达式树)+类库(Lambda表达式树)+类库(LinqtoSql)+类库(LinqtoObject)+类库(LinqtoXml)+类库(Linqto其他扩展)
解决方案五:
LinqMSN群linqchina@hotmail.com
解决方案六:
呵呵,Linq本质没有超出.Net2.0,Bill同学已经说了阿
解决方案七:
引用3楼vwxyzh的回复:
Linq的本质=语法糖(自动属性)+语法糖(初始化器)+语法糖(具有隐式类型的局部变量)+语法糖(匿名类型)+语法糖(扩展方法)+语法糖(更强的类型自动推断)+语法糖(Lambda表达式)+语法糖(编译为Lambda表达式树)+类库(Lambda表达式树)+类库(LinqtoSql)+类库(LinqtoObject)+类库(LinqtoXml)+类库(Linqto其他扩展)
vwxyzh真强啊!
解决方案八:
mark
解决方案九:
学习!
解决方案十:
该回复于2008-03-16 10:31:12被版主删除
解决方案十一:
:-)拜读。
解决方案十二:
学习
解决方案十三:
纠正一下楼主,第一条,自动属性,“//C#3.0属性可以给getset加访问修饰符”c#2.0也可以这么做:)
解决方案十四:
表达式树没有讲.LinqtoSql里很重要的概念.不过也不错了.
解决方案十五:
Lambda可不是语法糖。Lambda晚期执行是LINQ的核心。
解决方案:
学习
解决方案:
好文。
解决方案:
查收
解决方案:
up
解决方案:
引用3楼vwxyzh的回复:
Linq的本质=语法糖(自动属性)+语法糖(初始化器)+语法糖(具有隐式类型的局部变量)+语法糖(匿名类型)+语法糖(扩展方法)+语法糖(更强的类型自动推断)+语法糖(Lambda表达式)+语法糖(编译为Lambda表达式树)+类库(Lambda表达式树)+类库(LinqtoSql)+类库(LinqtoObject)+类库(LinqtoXml)+类库(Linqto其他扩展)
解决方案:
有点难度哦
解决方案:
该回复于2008-05-09 11:19:16被版主删除
解决方案:
关注,收藏
解决方案:
不错。Linq还是很方便的。
解决方案:
学习了,正准备学呢
解决方案:
拜读!
解决方案:
mark一下,收藏
解决方案:
天上什么在飞?
解决方案:
被楼主那么一指点豁然开朗啊
解决方案:
语法糖是什么东西?
解决方案:
不错。。
解决方案:
收藏~谢谢
解决方案:
不错。简单的总结了一下。
解决方案:
Linq的本质=(自动属性)+(初始化器)+(具有隐式类型的局部变量)+(匿名类型)+(扩展方法)+(更强的类型自动推断)+(Lambda表达式)+(编译为Lambda表达式树)+(Lambda表达式树)+(LinqtoSql)+(LinqtoObject)+(LinqtoXml)+(Linqto其他扩展)
解决方案:
学习!
解决方案:
顶一个
解决方案:
阅~~~~~~~~~
解决方案:
LINQ可不是语法糖 它是真正地提高了程序员的表达能力 LINQ的语法说实话很简单 背后的编程思想可不简单