版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、 HYPERLINK blo/yuyijq/archive/2008/07/15/1243714.html 走进Linq-Linq横空出世篇 某日编程大师云游到某处,见一刚毕业不久学过两天C#和两天SQL的coder在那里发牢骚,为啥我要写这么多for,这么多if才能查询出我需要的数据,为啥我不能像SQL那样,发送一条命令告诉数据库我需要啥样的数据,它就给我返回来。 编程大师如是说:傻小子,像SQL那叫第四代编程语言,常存在于象牙塔和研究所里面的学究语言,还有个高雅的名字:函数编程。它只需要你告诉它要什么,而不需要告诉它怎么做。而你使用的C#语言属于命令式编程,你必须像发送命令一样一步步的告诉
2、你的机器怎么做。发牢骚的coder回了一句:不懂,我只是想不通,数据库能做这样的处理,为啥C#这么牛的语言不能呢。编程大师心里想着:这是不可能的事情,因为C#它是强类型语言,)*&)(&)*)()*&%&%&(后面省去200字)。天色还未晚,编程大师就急匆匆的回家了,他心里一直记着那位发牢骚的coder的话:为什么不能,为什么不能。晚上,编程大师做了一个梦,一个奇怪的梦,他的师傅“白眉”只说了三个字母:DSL。编程大师想着,DSL,领域专用语言,师傅要对我说什么呢,难道和今天我遇见的事有关?上面这段文字是一段调侃,调节一下气氛,呵呵。我觉得Linq就是一种DSL,在C#等常规语言上抽象起来的,
3、面向数据处理领域的特定“语言”,当然,它的根基还是这些常规语言。select,from,where,group等关键字本来只是在SQL里出现,现在把它们引入到C#这些常规编程语言中。那C#等是如何做到的呢?是在CLR底层支持的么?不是。既然“编译器”可以将C#编译成MSIL,那为什么编译不能干更多一点事情?将这些为了领域编程而出现关键字编译成原始语法。 下面还是从实例来说明吧:我们有一个图书类Book,先已经有一个填充有数据的Book集合,我们需要从这个集合里查找出单价小于50的书籍:usingSystem;/*/图书类/publicclassBook/*/图书名称/publicstringT
4、itleget;set;/*/单价/publicfloatPriceget;set;/*/作者/publicstringAuthorget;set;/*/ISBN号/publicstringISBNget;set;如是我可以写这样的代码:publicstaticclassHelperpublicstaticIListSearchBookByPrice()IListbooks=/./初始化一个Book集合IListresults=newList();foreach(Bookbookinbooks)if(book.Price50)results.Add(book);returnresults;现在
5、是根据单价查找,那如果我要按照书籍名称查找或者按照作者查找怎么办?那只有重写这个方法了。但是你想想,我们的查找条件到最后只不过是一个true或者false,只要if()里面的表达式为true我们就将其添加到返回结果的集合中,我才不管里面的表达式详细的是什么呢,ok,那这样我们就可以进一步改进这个方法了:publicstaticclassHelperpublicdelegateboolCondtion(Bookbook);publicstaticIListSearchBook(Condtioncondition)IListbooks=/./初始化一个Book集合IListresults=newL
6、ist();foreach(Bookbookinbooks)if(condition(book)results.Add(book);returnresults;看看我们如何调用改进后的方法:publicboolConditionTitle(Bookbook)returnbook.Title=yuyi;IListresults=Helper.SearchBook(newCondition(ConditionTitle);我们将查询条件使用委托解决了,只要传递一个接收Book作为参数,返回bool值的方法进去就可以查询满足条件的书籍了,但是,为了这个委托,我们还得先定义一个新方法,然后。太麻烦了,
7、为此C# 2.0为我们提供了匿名方法,专门针对这些只有“一句话方法”:IListresults=Helper.SearchBook(delegate(Bookbook)returnbook.Title=yuyi;);代码是减少不少,可这种写法还是不“人性化”,这还是一种人向计算机妥协的结果,才产生了这种怪异的写法,如是C# 3.0给我们提供了Lambda表达式:IListresults=Helper.SearchBook(book=book.Title=yuyi);代码更短了,写法也越来越向人类语言靠近了(这也许就是计算机语言的发展历史,随着计算机越来越智能,总有一天必会是计算机向人类妥协)。
8、不过这里还有一点不爽,每一次调用这个查找方法都要带Helper,要是IList自己就这个方法该多好。这个想法很好,C# 3.0里还为我们提供了扩展方法:publicstaticclassHelperpublicdelegateboolCondtion(Bookbook);publicstaticIListWhere(thisIListbooks,Condtioncondition)IListresults=newList();foreach(Bookbookinbooks)if(condition(book)results.Add(book);returnresults;仔细比较一下这个实现与
9、刚才的实现有何不同(我们还给它起了一个更好听的名字Where,是不是和SQL更像了),现在我们可以这样调用了:IListresults=books.Where(book=book.Title=yuyi);Books是一个IList,这行代码是多么的自然而优雅。依葫芦画瓢,我们可以到处这样书写代码了,不仅仅可以查找书籍,还可以查找帐户,一切处理集合查找的方法我都希望这样做,终于有一天你厌烦了,查找书,查找帐户,等等,他们之间没有什么差异,为什么我们要做这么多重复的工作呢,所有的IList都继承自IEnumerable,我们为啥不给IEnumerable添加一个Where方法,这样我们不就一劳永逸
10、了么,现在该是泛型施展才华的地方了:publicstaticclassHelperpublicdelegateboolCondtion(Tt);publicstaticIEnumerableFindBy(thisIEnumerableitems,Condtioncondition)foreach(Ttinitems)if(condition(t)/C#2.0里出现的一个关键字,返回一个迭代器yieldreturnt;现在,不管是IList还是IList都可以使用这个Where方法了但是做集合操作的时候我们不仅仅需要Where,还需要OrderBy,Group等等,我想把所有的SQL能干的都移植
11、过来。当然微软也意识到了这点,如是在.net 3.5里,微软发布了我们梦寐以求的Linq,将查询集成到语言里面来。它给IEnumerable添加了很多扩展方法,这样你可以很自然的去调用。你可以使用Reflector打开System.Core.dll,打开System.Linq命名空间,在这个命名空间里有一个Enumerable类,这里面就是微软为我们添加的扩展方法,看看,是不是SQL里所有的东西都可以在这里找到了。 好了,就此搁笔吧,这一篇作为我的走进Linq系列的开篇,在接下来我会为你把Linq大卸八块。 HYPERLINK blo/yuyijq/archive/2008/07/16/124
12、4750.html 走进Linq-辉煌的背后罗马不是一天建成的,千里之行始于足下,美丽的Linq也不是一蹴而就的。Linq是给一些语言特性披上了一层漂亮的外衣。那纺织Linq漂亮的外衣又需要哪些金针银线呢?在本篇有四个小节,每个小节分别阐述一个语言特性,这些特性都将为Linq而服务,没有它们也没有未来的Linq。在文中不仅仅写到了这些特性的用法,还揭示了他们背后发生的事情,也加上了我对这些特性的一些理解。 HYPERLINK blo/yuyijq/archive/2008/07/16/1244657.html t _blank 扩展方法 没有扩展方法,Linq的实现肯定不会再像现在这么优雅,在
13、本篇中我将首先描述扩展方法的应用,然后从IL层面解释扩展方法的实现,最后给出一些应用扩展方法的原则 HYPERLINK blo/yuyijq/archive/2008/07/16/1244736.html t _blank 匿名方法和Lambda表达式 Lambda表达式将函数式编程风格带进了C#这种命令编程语言中,Lambda表达式可以编译成表达式树,将表达式树说成Linq的根基我想一点都不为过吧 HYPERLINK blo/yuyijq/archive/2008/07/16/1244460.html t _blank 匿名类型与隐式类型局部变量如果没有隐式类型局部变量,使用Linq查询的时
14、候不会再像现在这么轻松吧 HYPERLINK blo/yuyijq/archive/2008/07/16/1244433.html t _blank 对象集合初始化器这个可以减少很多无意义的代码这些文章我都发布在新手区,这里只是做个索引,如果感兴趣的可以去拍两下砖。这一篇就算为后面的Linq铺路吧,精彩无需等待:。 HYPERLINK blo/yuyijq/archive/2008/07/18/1245874.html 走进Linq-Linq大观园 文章发布后大家有些人叫做,心里窃喜,不过压力也大增,我很想按照简洁明快的文风写下去,不过讲技术的文章很难不落于沉闷,所以我努力了。(题外话:这几天
15、猛看幽默小说,想把文字写的幽默一点,开个玩笑,呵呵)经过几天的闭关编程大师又有了一些新的觉悟了,不管对DSL还是命令式编程和函数式编程都有了新的理解。如是他又接着了漫长的云游。第一站当然就是那个曾经让他结下心结的那个刚毕业的coder.大师:“嘿,这几日可好,还在发牢骚么?”Coder:“不了,正好你来了,让你看看我的程序”,Coder将他的电脑屏幕转向大师,期盼的眼神表明他急切的期望得到大师的夸奖。如是大师看到了如下一些代码:/一个通用的泛型委托,代表接受一个参数并有一个返回值的方法/输入参数类型/返回值类型/输入参数/返回值publicdelegateTOutputMyDelegate(T
16、Inputinput);/这个类是包含有对IEnumerable接口的一系列扩展方法/因为在.net里所有的集合类都实现了IEnumerable接口/所以对该接口的扩展将扩散到所有集合/publicstaticclassExtensionpublicstaticIEnumerableWhere(thisIEnumerableself,MyDelegatefilter)foreach(TInputiteminself)if(filter(item)yieldreturnitem;publicstaticIEnumerableSelect(thisIEnumerableself,MyDelegat
17、eselector)foreach(TInputiteminself)yieldreturnselector(item);/下面有更多的SQL风格的移植下面是我做的个小测试代码:publicclassProgrampublicstaticvoidMain()IListbooks=newListnewBookTitle=InsideCOM,ISBN=123-456-789,Price=20,newBookTitle=InsideC#,ISBN=123-356-d89,Price=100,newBookTitle=Linq,ISBN=123-d56-d89,Price=120;varresult=
18、books.Where(book=book.Title=Linq).Select(book=newKey=book.Title,Value=book.Price);Coder一边展示着代码,一边念叨着,这里是因为使用了“扩展方法”所以可以这样写,这里使用了Lambda表达式,它可以简化匿名方法的写法,这里编程大师一边听着coder的讲解,一遍频频点头:“傻小子,不错啊,有点当年我的影子,按照你这样下去罗马也可以建成了,Linq也是可以写出来的呀。”Coder听到大师的话兴奋异常,不过他从这句话里还是捕捉到了一个陌生的词汇:Linq。他用诧异的眼神看着大师,问道:”啥是Linq,是谁家又创造了个
19、新词汇?”大师笑着说,其实你刚才做的微软已经帮你做了,还给它起了一个非常洋气的名字:Linq,中文名字呢就叫做 语言集成查询。在.net 3.5发布的时候,微软新发布了几个dll,其中有一个就叫做System.Core.dll,在这个dll下对一些System命名空间做了进一步扩展。在System.Core.dll下的System命名空间下你会发现有这么几个泛型的委托:/无参,有一个返回值publicdelegateTResultFunc();/有一个参数和一个返回值,和你那个MyDelegate一样publicdelegateTResultFunc(Targ);/两个参数一个返回值publi
20、cdelegateTResultFunc(T1arg1,T2arg2);/三个参数一个返回值publicdelegateTResultFunc(T1arg1,T2arg2,T3arg3);/四个参数一个返回值publicdelegateTResultFunc(T1arg1,T2arg2,T3arg3,T4arg4);有了这几个泛型的委托基本上都能应付了吧。还是在这个dll下有个System.Linq命名空间,这是Linq的核心命名空间,这里面有个名为 HYPERLINK http:/ Enumerable的静态类,它里面的方法都是对IEnumerable(这个接口可是Linq的中心人物啊)这个
21、接口的扩展方法。看看,是不是在SQL里能用的这里都能找到了?Select,Where,OrderBy, HYPERLINK http:/ OrderByDescending,Average,Distinct所以你现在很简单的就可以写出像下面这样的代码了:result=books.Where(book=book.Title.StartsWith(I).OrderBy(book=book.Price).Select(book=newKey=book.Title,Value=book.Price);编程大师接着说:如果就这样算了,我觉得Linq也不过尔尔,增加一些扩展方法而已,但是现在微软比我们想象
22、的走的更远,现在你不仅仅能对程序中的一些集合对象做这样的查询了,你想想我们平时的程序可以归结为怎样一个等式?还没等coder说出口大师就在键盘上敲下:程序=代码+数据编程大师如是接着说:那这些数据平时都来源于哪里?Coder:程序中自己构造的一些集合对象,像我刚才的代码中那样,还有数据库,这个使我们平时用到最多的,还有XML存储,还有WebService,这个来源于远程的数据,还有什么RSS啦等等,很多了。编程大师:嗯,是的。数据的来源非常广泛,就说我们平常用的三个吧,内存中的集合对象、XML存储和数据库。对于内存中的集合对象我们有语言自身的支持,XML我们有XML的一些API,比如XPath
23、,对于数据库我们有ADO.net,可实际上从抽象层面我们对这些数据的操作都是相同的,你想不想屏蔽掉存储的细节,在高层有一个统一的API访问这些数据呢?至于数据存储在哪里对于你是透明的,也许它存在于你内存中,也许在万网的机房也许在美国西雅图,但是对于你来说这些都无需关心,你的代码都一样。Coder:听起来是个很美妙的事情,这不会是在做梦吧。大师:不是在做梦,今天你已经有了这些方法在.net 3.5里微软还发布了另外两个dll:System.Data.Linq.dllSystem.Xml.Linq.dll在System.Data.Linq.dll里,对数据库的查询做了支持,不过目前微软提供的只支持
24、Sql Server,感谢开源社区,现在有了DbLinq,它提供了对MySql,Oracle,Sql Server,PostgreSql,Sqlite的支持。System.Xml.Linq.dll在更高层次对Xml的访问做了支持这样你从微软这里获得了:Linq to Objects 对内存中的集合的支持Linq to Xml 对Xml的支持Linq to SQL 对Sql Server的支持 这是一张从Linq in Action那本书里的截图,该图很好的在一个大的层次上揭示了Linq的视图。C#、等一系列.net语言在一些语言特性和Linq对语言的扩展上对Linq家族提供了支持。未来我们将会
25、实现Linq in Everywhere,Linq将成为你的变成习惯。C#对Linq的语言层面支持使用result=books.Where(book=book.Title.StartsWith(I).OrderBy(book=book.Price).Select(book=newKey=book.Title,Value=book.Price);这种方式编写代码,虽然减少了不少工作量,并且编程风格也更加人性化,不过现在C#为我们提供了一些列非常有用的关键字。上面的代码现在你可以这样来编写:result=frombookinbookswherebook.Title.StartsWith(I)ord
26、erbybook.PriceselectnewKey=book.Title,Value=book.Price;from关键字后面跟着的是 HYPERLINK http:/ Func委托的输入参数,in关键字后面跟着一个IEnumerable类型,where,orderby,select对应着那些扩展方法,那些扩展方法接受的委托的输入参数就是from后面的book。实际上你可以把这些代码写成一行意思就更明显了:result=frombookinbookswherebook.Title.StartsWith(I)orderbybook.PriceselectnewKey=book.Title,Va
27、lue=book.Price;从books集合里枚举一个book,如果这个book的标题是以”I”开头的就把它加入到返回集合中,并把返回集合按照book的价钱排序将上面的代码编译后的程序集用Reflector反编译,生成的代码是:books.Where(delegate(Bookbook)returnbook.Title.StartsWith(I);).OrderBy(delegate(Bookbook)returnbook.Price;).Select(delegate(Bookbook)returnnewKey=book.Title,Value=book.Price;);看来这种方式写和扩
28、展方法调用的方式没有什么差别,那为什么不呢。废话那么多了,还是来几个HelloWorld式的程序吧 HelloWorld Linq(下面所有程序的Book就是本系列文章中第一篇所出现的Book类)有一个Book集合,但是这个集合具体存储哪里我们并不清楚,也许在内存,也许在数据库,也许在XML存储,我们要做的就是把价格大于50的给揪出来,然后按照价格排序。Linq to Objects(从内存中的集合里查找)数据准备阶段/这样的一个集合,存储在内存中IListbooks=newListnewBookTitle=InsideCOM,ISBN=123-456-789,Price=20,newBook
29、Title=InsideC#,ISBN=123-356-d89,Price=100,newBookTitle=Linq,ISBN=123-d56-d89,Price=120;数据查询阶段varresult=frombookinbookswherebook.Price50orderbybook.PriceselectnewKey=book.Title,Value=book.Price;foreach(variteminresult)Console.WriteLine(Key:0-Value:1,item.Key,item.Value.ToString();Linq to SQL(集合存储在Sql
30、 Server) 数据准备阶段建立数据库表输入数据改写一下Book类,这个类是一个映射类,和数据库表做映射,更多内容后面会详细讲解TablepublicclassBook/图书名称/ColumnpublicstringTitleget;set;/单价/Column(DbType=numeric(5,2)publicfloatPriceget;set;/作者/ColumnpublicstringAuthorget;set;/ISBN号/ColumnpublicstringISBNget;set;数据查询阶段DataContextdb=newDataContext(DataSource=local
31、host;InitialCatalog=db;UserID=sa;Password=sa);varresult=frombookindb.GetTable()wherebook.Price50orderbybook.PriceselectnewKey=book.Title,Value=book.Price;foreach(variteminresult)Console.WriteLine(Key:0-Value:1,item.Key,item.Value.ToString();最后程序运行的结果都是:真所谓殊途同归啊,不管数据是如何存储的,查询的方式却99%一致。 总结本篇旨在给大家一个对Li
32、nq的大局观认识,没有详细的深入,就算一个总览吧。精彩无需等待,祝大家编程愉快。 HYPERLINK blo/yuyijq/archive/2008/07/16/1244433.html 不能不说的C#特性-对象集合初始化器本系列文章连接:不能不说的C#特性-对象集合初始化器 HYPERLINK blo/yuyijq/archive/2008/07/16/1244460.html t _blank 不能不说的C#特性-匿名类型与隐式类型局部变量 HYPERLINK blo/yuyijq/archive/2008/07/16/1244657.html t _blank 不能不说的C#特性-扩展方
33、法 HYPERLINK blo/yuyijq/archive/2008/07/16/1244736.html t _blank 不能不说的C#特性-匿名方法和Lambda表达式 HYPERLINK blo/yuyijq/archive/2008/07/18/1246190.html 不能不说的C#特性-迭代器(上)及一些研究过程中的副产品 HYPERLINK blo/yuyijq/archive/2008/07/19/1246609.html 不能不说的C#特性-迭代器(下),yield以及流的延迟计算在写一些实体类的时候,我们往往在写构造方法的时候思考很长时间,除了一个无参构造器外还在想需要
34、写几个构造器呢?哪些参数是需要初始化的。现在你再也不需要为这事烦恼了。C# 3.0为你提供了对象集合初始化器:/图书类/publicclassBook/图书名称/publicstringTitleget;set;/单价/publicfloatPriceget;set;/作者/publicstringAuthorget;set;/ISBN号/publicstringISBNget;set;/对象初始化器Bookbook=newBookTitle=InsideCOM,ISBN=123-456-789;现在你想初始化几个就初始化几个,不需要出现这种情况:publicBook():this()publ
35、icBook(stringtitle):this(title,0)publicBook(stringtitle,floatprice):this(title,price,)publicBook(stringtitle,floatprice,stringisbn)this.Title=title;this.Price=price;this.ISBN=isbn;这一串的构造方法都是为了应付不同的初始化情况。好了,来看看对象初始化器编译器在后面为我们做了些什么呢?使用Reflector反编译程序集:Bookg_initLocal0=newBook();g_initLocal0.Title=Insid
36、eCOM;g_initLocal0.ISBN=123-456-789;Bookbook=g_initLocal0;C#编译器生成了一个新的局部变量g_initLocal0,调用Book的默认无参构造方法初始化它,然后对它的属性进行赋值,最后将这个局部变量赋值给book。看到这里,我们应该想到,要使用对象初始化器,那么这个对象必须有一个无参构造方法,如果你给这个方法写了一个有参构造方法而将它的默认无参构造方法覆盖了并且没有提供一个新的无参构造方法,那么使用对象初始化器编译的时候是不会通过的(不过想不通,为啥C#编译器生成这么一个奇怪的局部变量名字,还有为啥不直接使用book呢)。像下面的代码不更
37、好:Bookbook=newBook();book.Title=InsideCOM;book.ISBN=123-456-789;后来我发现我是在debug模式下编译的,换到release模式下变成了这样:Bookg_initLocal0=newBook();g_initLocal0.Title=InsideCOM;g_initLocal0.ISBN=123-456-789;被优化了。上面介绍的就是对象初始化器了,那什么是集合初始化器呢?IListbooks=newList();/这里就使用了对象初始化器,学以致用吧books.Add(newBookTitle=InsideCOM,ISBN=12
38、3-456-789,Price=20);books.Add(newBookTitle=InsideC#,ISBN=123-356-d89,Price=100);books.Add(newBookTitle=Linq,ISBN=123-d56-d89,Price=120);这样的代码没少写吧,实际上也许比这更复杂,有了C# 3.0我们睡觉都想笑:IListbooks=newListnewBookTitle=InsideCOM,ISBN=123-456-789,Price=20,newBookTitle=InsideC#,ISBN=123-356-d89,Price=100,newBookTitl
39、e=Linq,ISBN=123-d56-d89,Price=120;还是像刚才一样,我们来欣赏一下C#编译器为我们生成的代码:Listg_initLocal0=newList();Bookg_initLocal1=newBook();g_initLocal1.Title=InsideCOM;g_initLocal1.ISBN=123-456-789;g_initLocal1.Price=20f;g_initLocal0.Add(g_initLocal1);Bookg_initLocal2=newBook();g_initLocal2.Title=InsideC#;g_initLocal2.IS
40、BN=123-356-d89;g_initLocal2.Price=100f;g_initLocal0.Add(g_initLocal2);Bookg_initLocal3=newBook();g_initLocal3.Title=Linq;g_initLocal3.ISBN=123-d56-d89;g_initLocal3.Price=120f;g_initLocal0.Add(g_initLocal3);从上面的代码来看,编译器自动的调用了List的无参构造方法,然后实例化一个个的Book,再一个个的Add进去,和我们原来的做法没有什么不同,但是,这是编译器为我们做的,所以简省了我们很多的
41、编码工作。 对象集合初始化器就算介绍完了。有人也许会说,不就是个syntx sugar么,有什么。是的,确实是个语法糖。在编译器发展早期,编译器科学家门一直在想方设法的优化编译器生成的代码,这个时候,编译器做的主要是对机器优化,因为那个时候机器的时间非常宝贵,机器运算速度也不快,今天我们有了足够好的机器了(但并不是说我们可以不关注性能的编写程序),而且作为编写软件的人来说,比机器的时间宝贵得多,所以今天的编译器也在向人优化了,从编程语言的发展之路来讲,今天的编程语言比昨天的语言更高级,也更人性化了,我们只要编写更少的代码,更符合人的思维的代码,而只要关注我们值的关注的地方。体力活儿就交给编译器
42、吧。附加:刚开始想想这对象集合初始化器也许就一鸡肋,没啥用,不就减少一点点代码么,像这种简单的初始化工作,大部分代码生成器都可以来干。后来在研究匿名类型的时候突然发现,如果没有这个对象初始化器,匿名类型是不是要复杂一些?或者就是难以实现?var test = newKey=test,Value=test;如果没有对象初始化器,匿名类型该怎么办? HYPERLINK blo/yuyijq/archive/2008/07/16/1244460.html 不能不说的C#特性-匿名类型与隐式类型局部变量本系列文章连接: HYPERLINK blo/yuyijq/archive/2008/07/16/1
43、244433.html t _blank 不能不说的C#特性-对象集合初始化器不能不说的C#特性-匿名类型与隐式类型局部变量 HYPERLINK blo/yuyijq/archive/2008/07/16/1244657.html t _blank 不能不说的C#特性-扩展方法 HYPERLINK blo/yuyijq/archive/2008/07/16/1244736.html t _blank 不能不说的C#特性-匿名方法和Lambda表达式 HYPERLINK blo/yuyijq/archive/2008/07/18/1246190.html 不能不说的C#特性-迭代器(上)及一些研
44、究过程中的副产品 HYPERLINK blo/yuyijq/archive/2008/07/19/1246609.html 不能不说的C#特性-迭代器(下),yield以及流的延迟计算 在本篇中我要介绍两个概念,我觉得这两个东西必须一起来介绍,这样才能连贯。C# 2.0里我们已经匿名方法了,现在类型也玩起匿名来了,怪不得大家“举报”的时候都喜欢匿名,为啥?因为匿名被举报人就找不着报复对象了呗,是的,匿名就是把名字隐藏起来,没有名字谁还能找得到你啊。 匿名类型在C#里有这样一些类型,它是作为临时储存数据的,生命周期只在这个方法内,方法结束了,这个类型的生命周期也没有了。那么这里我们就可以使用一个
45、匿名类型。varKeyPair=newKey=”yuyi”,Value=”20”;这个KeyPair就是一个匿名类型,注意KeyPair这里是一个变量名,并不是类的名字。嗯,前面还有一个var,这又是什么呢?这是C# 3.0里面的隐式局部变量。隐式类型局部变量还是先介绍一下隐式类型局部变量吧:在C# 3.0里多了一个关键字var,他表示这样的一种类型:C#编译器可以根据上下文推断的出来比如var I = 5;编译器可以根据后面的赋值推断的出来i应该是个整型。既然是局部变量,那么它就只能用在方法内部了,注意C#是强类型的,引入了一个var并不是像javascript那样,变成了一个弱类型的语言。
46、在编译器第一次编译后var就会被确定的类型所替代的。所以对于隐式类型局部变量要注意以下几点: 1. 它只能存在于方法内部2. 它不是一个新的类型,只是一个关键字,或者叫做一个占位符,在C#编译器编译后它就会被确定的类型所替代3. 它是编译器根据上下文推断出来的,所以所有一切不能被编译器推断出来的用法都是错误的。比如不能这样使用:var nullValue = null;因为null啥也不是,他是一个空指针,是一个不确定的东西。也不能这样使用:var I = 5;I = “abc”;编译器根据第一个赋值会推断出它是一个整型,但是随后又将一个字符串赋值给它,这是怎么回事呢?对于var我的建议是不到
47、逼不得已的时候不用,那什么是逼不得已呢?来看我们的匿名类型吧。回到匿名类型刚才说了,匿名类型是没有名字的类型,没有名字你怎么来称呼它,怎么来声明它?但是匿名类型真的是没有名字的么?看看C#编译器又在我们背后干了些什么:使用ILDASM打开编译过的程序集,发现多了一个类型:f_AnonymousType0j_TPar,j_TPar这个类型是直接继承自System.Object的,并且是internal seald(只在程序集内可见,并且不能被继承)。有心的你也许会发现,这个类型还是一个泛型类型,那么只要我们在使用一个匿名类型的时候参数个数,参数名称不发生变化,编译器是不会为我们产生更多的类型的:
48、varKeyPair1=newKey=yuyi,Value=Programer;varKeyPair2=newKey=y,Value=3;varKeyPair3=newKey=4,Value=abc;上面三个匿名类型,编译器只会为我们在背后产生一个新类型,一个泛型的新类型。如果我们将这个匿名类型内的属性名修改一下:对varKeyPair1=newKey=yuyi,Value=Programer;varKeyPair2=newKey=y,Value1=3;就会产生两个新泛型了:f_AnonymousType0j_TPar,j_TParf_AnonymousType1j_TPar,j_TPar看看
49、,这个命名还是有规律可循哦。如果你给这个匿名类型添加一个新属性呢?这样又产生了一个新类型了:f_AnonymousType1j_TPar,j_TPar,j_TPar嗯,这个问题还是值得关注的,所以我们在使用匿名类型的时候应该尽量保持“一致性”:属性个数一致(这个尽量了)。属性名称一致,这个比较好把握。只要保持了这个一致性,编译器会为一致的产生同一个类型,而不一致的会新产生一个类型,如果不一致的太多我想是不是会产生“代码爆炸”而致使”WorkSet”过大造成性能的损失?这个只是我个人认为,没有经过测试。继续隐式类型局部变量由于匿名类型在我们编写代码的时候并不存在,所以匿名类型也不能作为方法的返回
50、值和参数了。”var”一样,也是只能在方法内部使用。现在是不是有点明白什么时候才是逼不得已使用”var”啊?就是在使用匿名类型的时候,匿名类型编译器可以推断出来,但是靠人工又无法推断了。所以我觉得只在编译器可推断而人不可推断的时候才使用隐式类型局部变量,靠我们人工可以推断的还是不建议使用,显式的声明变量类型可以增强代码的可读性,这是一个好的编程习惯,不要因为C# 3.0提供了这样的特性就大用而特用。 HYPERLINK blo/yuyijq/archive/2008/07/16/1244657.html 不能不说的C#特性-扩展方法本系列文章连接: HYPERLINK blo/yuyijq/a
51、rchive/2008/07/16/1244433.html t _blank 不能不说的C#特性-对象集合初始化器 HYPERLINK blo/yuyijq/archive/2008/07/16/1244460.html t _blank 不能不说的C#特性-匿名类型与隐式类型局部变量不能不说的C#特性-扩展方法 HYPERLINK blo/yuyijq/archive/2008/07/16/1244736.html t _blank 不能不说的C#特性-匿名方法和Lambda表达式 HYPERLINK blo/yuyijq/archive/2008/07/19/1246609.html 不
52、能不说的C#特性-迭代器(下),yield以及流的延迟计算在我们的编程生涯中我们要使用很多很多类库,这些类库有的是我们自己开发的,我们有她的代码,有的是第三方发布的,我们不仅没有他们的代码,连看的机会都没有。作为.net程序员,我们每天都要和BCL(Base Class Linbrary)打交道。无疑,BCL做为一个年轻的框架类库,她是成功的,但是还有一些时候我们还是得写一些”Helper”方法来扩展类库,由于我们不能修改类库的源代码,我们只有写一个个的静态类。虽然在使用上也算方便,但作为追求完美的程序员来说总有些不雅。现在我就碰到这样的事情,前两天奉命写一个从XML文件加载Chart图的设置
53、的方法,从XML加载数据绑定到对象上,这肯定是反射的用武之地了。我经常需要写一些根据对象属性名字来判断这个对象是否有这个属性或者根据属性名获取该属性的值。还是按照平常一样,我很快写了一个PropertyHelper,里面有两个静态方法:HasProperty,GetValueByName。PropertyHelper.HasProperty(point, X),如此的调用也还过得去,不过在C# 3.0微软为我们提供了扩展方法。现在我们可以直接这样调用了point.HasProperty(“X”);看看我是如何实现这个扩展方法的?publicstaticclassPropertyExtensio
54、npublicstaticobjectGetValueByName(thisobjectself,stringpropertyName)if(self=null)returnself;Typet=self.GetType();PropertyInfop=t.GetProperty(propertyName);returnp.GetValue(self,null);我给object类型添加了一个扩展方法,在.net里所有的类都继承自object,那所有的类都默认的拥有这个方法了,真方便,呵呵。注意到和普通的静态方法有何差别?在这个方法的第一个参数前面多了一个this关键字。扩展方法:1 方法所在
55、的类必须是静态的2 方法也必须是静态的3 方法的第一个参数必须是你要扩展的那个类型,比如你要给int扩展一个方法,那么第一个参数就必须是int。4 在第一个参数前面还需要有一个this关键字。按照上面的步骤写你就得到了一个“扩展方法”,你可以像调用这个类的原生方法那样去调用它:stringstr=abc;objectlen=str.GetValueByName(Length);好像string类型现在有了GetValueByName这个方法一样,但实际上string并没有这样一个方法。那这又是为什么呢?是我们可爱的编译器在其中做了手脚。为了避开编译器的干扰,我们来直接欣赏MSIL代码:L_00
56、08:ldstrLengthL_000d:callobjectTestLambda.PropertyExtension:GetValueByName(object,string)从MSIL中我们可以看出,这段代码编译后和调用静态方法没有任何的差别(从call指令来看,这是在调用一个静态方法)。从这里可以知道扩展方法即可以使用实例调用的方式也可以直接使用静态类调用的方式:str.GetValueByName(Length);PropertyExtension.GetValueByName(str,Length);下面将对扩展方法做一些细节的介绍:Visual Studio 2008对扩展方法有智
57、能感知的支持,如下图: 在方法的图标上有一个与其他的都不相同,他的突变下面还带有一个蓝色的向下的箭头,这就表明这个方法是一个扩展方法。下面是对编写扩展方法要注意的几个原则(当然,仁者见仁、智者见智,这也是一家之言):扩展方法有就近原则,也就是如果在你的程序里有两个一模一样的扩展方法,一个和你的使用类是处于同一命名空间里,另外一个处于别的命名空间里,这个时候会优先使用同一命名空间里的扩展方法,也就是说“血缘关系”越近,越被青睐。很多人看到扩展方法也许眼里冒出金光,以后在设计的时候不管三七二十一,反正可以扩展。还有一些人会对类任意扩展,将以前一些作为”Helper”的方法统统使用扩展方法代替,注意
58、的是扩展方法有“污染性”,所以我觉得在扩展的时候还是想想,是不是值得这样扩展。在扩展的时候也不要对比较高层的类进行扩展,像我上面对object的扩展我觉得就是不可取的,object是所有类的基类,一经扩展,所有的类都被“污染”了。发表与2008-07-16 于2008-08-06第一次更新 HYPERLINK blo/yuyijq/archive/2008/07/16/1244736.html 不能不说的C#特性-匿名方法和Lambda表达式本系列文章连接: HYPERLINK blo/yuyijq/archive/2008/07/16/1244433.html t _blank 不能不说的C
59、#特性-对象集合初始化器 HYPERLINK blo/yuyijq/archive/2008/07/16/1244460.html t _blank 不能不说的C#特性-匿名类型与隐式类型局部变量 HYPERLINK blo/yuyijq/archive/2008/07/16/1244657.html t _blank 不能不说的C#特性-扩展方法不能不说的C#特性-匿名方法和Lambda表达式 HYPERLINK blo/yuyijq/archive/2008/07/18/1246190.html 不能不说的C#特性-迭代器(上)及一些研究过程中的副产品 HYPERLINK blo/yuyi
60、jq/archive/2008/07/19/1246609.html 不能不说的C#特性-迭代器(下),yield以及流的延迟计算 在我们程序中,经常有这样一些需求:1. 需要一个临时方法,这个方法只会使用一次,或者使用的很少。2. 这个方法的方法体很短,以至于比方法声明都短,写起来实在没劲(我将其称之为“一句话方法”)。没办法,这样的方法写起来真是吃力不讨好,比如一些按钮事件处理中,有些按钮点击就是弹出一个对话框,或者调用一下别的什么方法。比如下面的代码:this.btnRefresh.Click+=newSystem.EventHandler(this.btnRefresh_Click);
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年度绿色建筑认证结算工程款合同样本2篇
- 2025年度民间借贷资产证券化业务法律文件制作合同4篇
- 二零二五年度教育培训机构品牌合作合同8篇
- 2025年土地承包经营权租赁备案合同样本3篇
- 二零二五版农家乐乡村旅游文创产品开发与销售合同4篇
- 二零二五年度全新境外派遣劳动合同范本下载与范本解读3篇
- 2025年度门窗行业供应链金融合作合同3篇
- 二零二五年度农田水电灌溉自动化工程合同
- 2025版灭蟑螂项目外包服务合同范本2篇
- 二零二五年度智慧农业设备采购与维护服务合同2篇
- 【寒假预习】专题04 阅读理解 20篇 集训-2025年人教版(PEP)六年级英语下册寒假提前学(含答案)
- 2024年智能监狱安防监控工程合同3篇
- 2024年度窑炉施工协议详例细则版B版
- 幼儿园篮球课培训
- 【企业盈利能力探析的国内外文献综述2400字】
- 统编版(2024新版)七年级《道德与法治》上册第一单元《少年有梦》单元测试卷(含答案)
- 100道20以内的口算题共20份
- 高三完形填空专项训练单选(部分答案)
- 护理查房高钾血症
- 项目监理策划方案汇报
- 《职业培训师的培训》课件
评论
0/150
提交评论