C# 3.X -- the newest features
微軟最近的動(dòng)作頻繁,C#2.0規(guī)范才剛推出不久,我還沒來的及完全消化C#2.0中的所有新特性,而今又推出了C#3.0,在短短幾年中,微軟就對(duì)C#進(jìn)行了兩次大的升級(jí),為C#加入了許多新的特性,從而使C#變得更加強(qiáng)大也更加現(xiàn)代了。下面我就把C#3.0中的新特性的要點(diǎn)列出來,以供大家快速瀏覽。
1:隱式類型化本地變量
這個(gè)特性非常簡(jiǎn)單,有些JavaScript的影子,我們可以統(tǒng)一使用使用"var"關(guān)鍵字來聲明局部變量,而不再需要指明變量的確切類型了,變量的確切類型可通過聲明變量時(shí)的初始值推斷出來。這樣一來,可以大大簡(jiǎn)化我們聲明局部變量的工作量了,下面是一個(gè)例子:
??????class?LocalVariables?:?AppRunner.AbstractApplication
??????{
??????????public?override?void?Run()
??????????{
??????????????var?intValue?=?5;
??????????????var?stringValue?=?"This?is?a?string";
??????????????var?customClass?=?new?LocalVariables();
??????????????var?intArray?=?new?int[3]?{?1,?2,?3?};
???
??????????????foreach?(var?value?in?intArray)
??????????????????Console.WriteLine(value);????????????
??????????}
??????}
上面的代碼將被解析成:
??????{
??????????public?override?void?Run()
??????????{
??????????????int?intValue?=?5;
??????????????string?stringValue?=?"This?is?a?string";
??????????????LocalVariables?customClass?=?new?LocalVariables();
??????????????int[]?intArray?=?new?int[3];
???
??????????????foreach?(int?value?in?intArray)
??????????????????Console.WriteLine(value);????????????
??????????}
??????}
??? 要特別注意的是,由于變量的類型是通過變量初始值推斷而來的,所以在聲明變量的同時(shí)必需為變量指定初始值。并且,變量并不是沒有類型的,變量一旦初始化之后,類型就確定下來了,以后就只能存儲(chǔ)某種類型的值了,比如上面的stringValue的類型經(jīng)推斷為string,所以該變量就只能保存string類型的值了。
2:匿名類型
有些時(shí)候我們需要臨時(shí)保存一些運(yùn)算的中間結(jié)果,特別是當(dāng)這些中間結(jié)果是由多個(gè)部份組成時(shí),我們常常會(huì)去聲明一個(gè)新的類型,以方便保存這些中間結(jié)果。表面上看起來這很正常,而細(xì)想之后就會(huì)發(fā)現(xiàn),這個(gè)新類型只服務(wù)于這個(gè)函數(shù),其它地方都不會(huì)再使用它了,就為這一個(gè)函數(shù)而去定義一個(gè)新的類型,確實(shí)有些麻煩。
現(xiàn)在,C#3.0中的匿名類型特性就可以很好的解決上面提到的問題,通過匿名類型,我們可以簡(jiǎn)單使用new { 屬性名1=值1, 屬性名2=值2, ..... , 屬性名n=值n }的形式直接在函數(shù)中創(chuàng)建新的類型,看下面這個(gè)例子:
class?AnonymousType?:?AppRunner.AbstractApplication??????{
??????????public?override?void?Run()
??????????{
??????????????var?anonymousType1?=?new?{
??????????????????CardNumber?=?"10001",?Name?=?"van's",?Sex?=?true
??????????????};
???
??????????????Console.WriteLine(anonymousType1.CardNumber);
??????????????Console.WriteLine(anonymousType1.Name);
???
??????????????var?anonymousType2?=?new?{
??????????????????CardNumber?=?"10002",?Name?=?"martin",?Sex?=?true
??????????????};
???
??????????????anonymousType2?=?anonymousType1;
??????????}
??????}
?
在新類型中只能有字段成員,而且這些字段的類型也是通過初值的類型推斷出來的。如果在聲明新的匿名類型時(shí),新類型的字段名、順序以及初始值的類型是一致的,那么將會(huì)產(chǎn)生相同的匿名類型,所以上例中anonymousType1和anonymousType2的類型是相同的,自然能進(jìn)行anonymousType2=anonymousType1的賦值。
3:隱式類型化數(shù)組
這個(gè)特性是對(duì)隱式類型化本地變量的擴(kuò)展,有了這個(gè)特性,將使我們創(chuàng)建數(shù)組的工作變得簡(jiǎn)單。我們可以直接使用"new[]"關(guān)鍵字來聲明數(shù)組,后面跟上數(shù)組的初始值列表。在這里,我們并沒有直接指定數(shù)組的類型,數(shù)組的類型是由初始化列表推斷出來的。
class?AnonymousTypeArray?:?AppRunner.AbstractApplication??????{
??????????public?override?void?Run()
??????????{
??????????????var?intArray?=?new[]?{?1,?2,?3,?4,?5?};
??????????????var?doubleArray?=?new[]?{?3.14,?1.414?};
??????????????var?anonymousTypeArray?=?new[]?{
??????????????????new?{?Name="van's",?Sex=false,?Arg=22?},
??????????????????new?{?Name="martin",?Sex=true,?Arg=23?}
??????????????};
???
??????????????Console.WriteLine(intArray);
??????????????Console.WriteLine(doubleArray);
??????????????Console.WriteLine(anonymousTypeArray[0].Name);
??????????}
??????}
上面的代碼中,anonymousTypeArray變量的聲明同時(shí)運(yùn)用了隱式類型化數(shù)組和匿名類型兩種特性,首先創(chuàng)建匿名類型,然后再初始值列表,推斷出數(shù)組的確切類型。
4:對(duì)象構(gòu)造者
我們?cè)诼暶鲾?shù)組時(shí),可以同時(shí)對(duì)其進(jìn)行初始化,這樣就省去了很多麻煩,但是在創(chuàng)建類的對(duì)象時(shí),這招可就不靈了,我們要么調(diào)用該類的構(gòu)造函數(shù)完成對(duì)象的初始化,要么就手工進(jìn)行初始化。這兩種方法都不太方便,使用構(gòu)造函數(shù)來對(duì)對(duì)象進(jìn)行初始化時(shí),我們?yōu)榱四撤N靈活性,可能需要編寫構(gòu)造函數(shù)的多個(gè)重載版本,實(shí)在是麻煩。
C#3.0中加入的對(duì)象構(gòu)造者特性,使得對(duì)象的初始化工作變得格外簡(jiǎn)單,我們可以采用類似于數(shù)組初始化的方式來初始化類的對(duì)象,方法就是直接在創(chuàng)建類對(duì)象的表達(dá)式后面跟上類成員的初始化代碼。具體示例如下:
????class?Point?????{
??????????public?int?X?{?get;?set;?}
??????????public?int?Y?{?get;?set;?}
???
??????????public?override?string?ToString()
??????????{
??????????????return?"("?+?X.ToString()?+?",?"?+?Y.ToString()?+?")";
??????????}
??????}
???
??????class?Rectangle
??????{
??????????public?Point?P1?{?get;?set;?}
??????????public?Point?P2?{?get;?set;?}
???
??????????public?Rectangle()
??????????{
??????????????P1?=?new?Point();
??????????????P2?=?new?Point();
??????????}
???
??????????public?override?string?ToString()
??????????{
??????????????return?"P1:?"?+?P1?+?",?P2:?"?+?P2;
??????????}
??????}
???
??????class?ObjectBuilder?:?AppRunner.AbstractApplication
??????{
??????????public?override?void?Run()
??????????{
??????????????Point?thePoint?=?new?Point()?{?X?=?1,?Y?=?2?};
??????????????Console.WriteLine("Point(X,?Y)?=?{0}",?thePoint);
???
??????????????Rectangle?theRectangle?=?new?Rectangle()?{?
??????????????????P1?=?{?X?=?1,?Y?=?1?},?P2?=?{?X?=?100,?Y?=?200?}?
??????????????};
??????????????Console.WriteLine(theRectangle);
??????????}
??????}
?
? 我們?cè)诙xPoint類的X和Y屬性時(shí),只須寫上該屬性的get和set訪問器聲明,C#編譯器會(huì)自動(dòng)為我們生成默認(rèn)的get和set操作代碼,當(dāng)我們需要定義簡(jiǎn)單屬性時(shí),這個(gè)特性非常有用。
我們以new Point() { X = 1, Y = 2 }語句,輕松的完成了對(duì)Point類的初始化工作。在創(chuàng)建類的對(duì)象時(shí),我們可以按照需要去初始化類的對(duì)象,只要在類的創(chuàng)建表達(dá)式后跟上要初始化屬性的列表即可,且可以只對(duì)需要初始化的屬性賦初值,而無需把所有屬性的初始值都寫上去。
在theRectangle對(duì)象的初始化表達(dá)式中,我們首先對(duì)P1屬性進(jìn)行初始化,然而P1屬性也是一個(gè)自定義的類型,所以P1屬性的初始化是另一個(gè)類型(Point)的初始化表達(dá)式,我們可以這樣的方式來對(duì)更加復(fù)雜的類型進(jìn)行初始化。
5:集合構(gòu)造者
我們可以在聲明數(shù)組的同時(shí),為其指定初始值,方法是直接在數(shù)組聲明的后面跟上初始值列表。這樣就使數(shù)組的初始化工作變得簡(jiǎn)單,而對(duì)于我們自己創(chuàng)建的集合類型,就無法享受到與普通數(shù)組一樣的待遇了,我們無法在創(chuàng)建自定義集合對(duì)象的同時(shí),使用數(shù)組的初始化語法為其指定初始值。
C# 3.0中加入的集合構(gòu)造者特性,可使我們享受到與普通數(shù)組一樣的待遇,從而在創(chuàng)建集合對(duì)象的同時(shí)為其指定初始值。為了做到這一點(diǎn),我們需要讓我們的集合實(shí)現(xiàn)ICollection<T>接口,在這個(gè)接口中,完成初始化操作的關(guān)鍵在于Add函數(shù),當(dāng)我使用初始化語法為集合指定初始值時(shí),C#編譯器將自動(dòng)調(diào)用ICollection<T>中的Add函數(shù)將初始列表中的所有元素加入到集合中,以完成集合的初始化操作。使用示例如下:
class?CollectionInitializer?:?AppRunner.AbstractApplication??????{
??????????class?StringCollection?:?ICollection<string>
??????????{
??????????????public?void?Add(string?item)
??????????????{
??????????????????Console.WriteLine(item);
??????????????}
???
??????????????//?Other?ICollection<T>?Members
??????????}
???
??????????public?override?void?Run()
??????????{
??????????????StringCollection?strings?=?new?StringCollection()?{?"Van's",?"Brog",?"Vicky"?};
??????????}
??????}
?
????? 在這個(gè)示例中,編譯器會(huì)自動(dòng)為strings對(duì)象調(diào)用Add方法,以將初始值列表中的所有元素加入到集合中,這里我們只是簡(jiǎn)單將初始值列表中的元素輸出到控制臺(tái)。
6:Lambda表達(dá)式
C# 2.0中加入的匿名代理,簡(jiǎn)化了我們編寫事件處理函數(shù)的工作,使我們不再需要單獨(dú)聲明一個(gè)函數(shù)來與事件綁定,只需要使用delegate關(guān)鍵字在線編寫事件處理代碼。
而C# 3.0則更進(jìn)一步,通過Lambda表達(dá)式,我們可以一種更為簡(jiǎn)潔方式編寫事件處理代碼,新的Lambda事件處理代碼看上去就像一個(gè)計(jì)算表達(dá)式,它使用"=>"符號(hào)來連接事件參數(shù)和事件處理代碼。我可以這樣寫:SomeEvent += 事件參數(shù) => 事件處理代碼;下面是完整的示例:
delegate?T?AddDelegate<T>(T?a,?T?b);???
??????class?LambdaExpression?:?AppRunner.AbstractApplication
??????{
??????????public?static?event?EventHandler?MyEvent;
???
??????????public?override?void?Run()
??????????{
??????????????MyEvent?+=?delegate(object?s,?EventArgs?e)
??????????????{
??????????????????Console.WriteLine(s);
??????????????};
???
??????????????MyEvent?+=?(s,?e)?=>?{?Console.WriteLine(s);?};
??????????????
??????????????MyEvent(this,?null);
???
??????????????AddDelegate<string>?add?=?(a,?b)?=>?a?+?b;
???
??????????????Console.WriteLine(add("Lambda",?"Expression"));
??????????}
??????}
?
????? 在上面的例子中,分別使用了匿名代理和Lambda表達(dá)式來實(shí)現(xiàn)同樣的功能,可以明顯看出Lambda表達(dá)式的實(shí)現(xiàn)更為簡(jiǎn)潔。我們?cè)谑褂肔ambda表達(dá)式編寫事件處理代碼時(shí),無需指明事件參數(shù)的類型,且返回值就是最后一條語句的執(zhí)行結(jié)果。
?
7:擴(kuò)展方法
當(dāng)我們需要對(duì)已有類的功能進(jìn)行擴(kuò)展時(shí),我們通常會(huì)想到繼承,繼承已有類,然后為其加入新的行為。而C# 3.0中加入的擴(kuò)展方法特性,則提供了另一種實(shí)現(xiàn)功能擴(kuò)展的方式,我們可以在不使用繼承的前提下實(shí)現(xiàn)對(duì)已有類本身的擴(kuò)展,這種方法并不會(huì)產(chǎn)生新的類型,而是采用向已有類中加入新方法的方式來完成功能擴(kuò)展。
在對(duì)已有類進(jìn)行擴(kuò)展時(shí),我們需將所有擴(kuò)展方法都寫在一個(gè)靜態(tài)類中,這個(gè)靜態(tài)類就相當(dāng)于存放擴(kuò)展方法的容器,所有的擴(kuò)展方法都可以寫在這里面。而且擴(kuò)展方法采用一種全新的聲明方式:public static 返回類型 擴(kuò)展方法名(this 要擴(kuò)展的類型 sourceObj [,擴(kuò)展方法參數(shù)列表]),與普通方法聲明方式不同,擴(kuò)展方法的第一個(gè)參數(shù)以this關(guān)鍵字開始,后跟被擴(kuò)展的類型名,然后才是真正的參數(shù)列表。下面是使用示例:
?????
static?class?Extensions??????{
??????????public?static?int?ToInt32(this?string?source)
??????????{
??????????????return?Int32.Parse(source);
??????????}
???
??????????public?static?T[]?Slice<T>(this?T[]?source,?int?index,?int?count)
??????????{
??????????????if?(index?<?0?||?count?<?0?||?index?+?count?>?source.Length)
??????????????{
??????????????????throw?new?ArgumentException();
??????????????}
???
??????????????T[]?result?=?new?T[count];
??????????????Array.Copy(source,?index,?result,?0,?count);????
??????????????return?result;
??????????}
??????}
???
??????class?ExtensionMethods?:?AppRunner.AbstractApplication
??????{
??????????public?override?void?Run()
??????????{
??????????????string?number?=?"123";
??????????????Console.WriteLine(number.ToInt32());
???
??????????????int[]?intArray?=?new?int[]?{?1,?2,?3?};
???
??????????????intArray?=?intArray.Slice(1,?2);
???
??????????????foreach?(var?i?in?intArray)
??????????????????Console.WriteLine(i);
??????????}
??????}
在上面的示例中,靜態(tài)的Extensions類中有兩個(gè)擴(kuò)展方法,第一個(gè)方法是對(duì)string類的擴(kuò)展,它為string類加入了名為ToInt32的方法,該方法沒有參數(shù),并返回一個(gè)int類型的值,它將完成數(shù)字字符向整數(shù)的轉(zhuǎn)換。有了這個(gè)擴(kuò)展方法之后,就可對(duì)任意string類的對(duì)象調(diào)用ToInt32方法了,該方法就像其本身定義的一樣。
第二個(gè)擴(kuò)展方法是一個(gè)范型方法,它是對(duì)所有數(shù)組類型的擴(kuò)展,該方法完成數(shù)組的切片操作。
C# 3.0中的Linq表達(dá)式,就是大量運(yùn)用擴(kuò)展方法來實(shí)現(xiàn)數(shù)據(jù)查詢的。
8:Linq查詢表達(dá)式
C# 3.0中加入的最為復(fù)雜的特性就是Linq查詢表達(dá)式了,這使我們可直接采用類似于SQL的語法對(duì)集合進(jìn)行查詢,這就使我們可以享受到關(guān)系數(shù)據(jù)查詢的強(qiáng)大功能。
Linq查詢表達(dá)式是建立在多種C# 3.0的新特性之上的,這也是我為什么最后才介紹Linq的原因。下面看一個(gè)例子:
class?LinqExpression?:?AppRunner.AbstractApplication??????{
??????????public?override?void?Run()
??????????{
??????????????//?定義匿名數(shù)組persons,?并為其賦初值
??????????????var?persons?=?new[]?{
??????????????????new?{?Name="Van's",?Sex=false,?Age=22?},
??????????????????new?{?Name="Martin",?Sex=true,?Age=30?},
??????????????????new?{?Name="Jerry",?Sex=false,?Age=24?},
??????????????????new?{?Name="Brog",?Sex=false,?Age=25?},
??????????????????new?{?Name="Vicky",?Sex=true,?Age=20?}
??????????????};
???
???
??????????????/**//*
??????????????????執(zhí)行簡(jiǎn)單Linq查詢
???
??????????????????檢索所有年齡在24歲以內(nèi)的人
??????????????????查詢結(jié)果放在results變量中
??
??????????????????results變量的類型與數(shù)組persons相同????????????????
??????????????*/
??????????????var?results?=?from?p?in?persons
????????????????????????????where?p.Age?<=?24
????????????????????????????select?p;
???
??????????????foreach?(var?person?in?results)
??????????????{
??????????????????Console.WriteLine(person.Name);
??????????????}
???
??????????????Console.WriteLine();
???
???
??????????????//?定義匿名數(shù)組customers,?并為其賦初值
??????????????//?該數(shù)組是匿名類型的
??????????????var?customers?=?new[]?{
??????????????????new?{
??????????????????????Name="Van's",?City="China",?Orders=new[]?{
??????????????????????????new?{
??????????????????????????????OrderNo=0,
??????????????????????????????OrderName="C#?Programming?Language(Second?Edition)",
??????????????????????????????OrderDate=new?DateTime(2007,9,?5)
???????????????????????????},
???????????????????????????new?{
??????????????????????????????OrderNo=1,
??????????????????????????????OrderName="Head?First?Design?Patterns(Chinese?Edition)",
??????????????????????????????OrderDate=new?DateTime(2007,9,15)
??????????????????????????},
??????????????????????????new?{
??????????????????????????????OrderNo=2,
??????????????????????????????OrderName="ASP.NET?Unleashed?2.0(Chinese?Edition)",
??????????????????????????????OrderDate=new?DateTime(2007,09,18)
??????????????????????????},
??????????????????????????new?{
??????????????????????????????OrderNo=3,
??????????????????????????????OrderName="The?C++?Programming?Langauge(Special?Edition)",
??????????????????????????????OrderDate=new?DateTime(2002,?9,?20)
??????????????????????????}
??????????????????????}
??????????????????},
??????????????????new?{
??????????????????????Name="Brog",?City="China",?Orders=new[]?{
??????????????????????????new?{
??????????????????????????????OrderNo=0,
??????????????????????????????OrderName="C#?Programming?Language(Second?Edition)",
??????????????????????????????OrderDate=new?DateTime(2007,?9,?15)
??????????????????????????}
??????????????????????}
??????????????????},
??????????????????new?{
??????????????????????Name="Vicky",?City="London",?Orders=new[]?{
??????????????????????????new?{?OrderNo=0,
??????????????????????????????OrderName="C++?Programming?Language(Special?Edition)",
??????????????????????????????OrderDate=new?DateTime(2007,?9,?20)
??????????????????????????}
??????????????????????}
??????????????????}
??????????????};
???
???
??????????????/**//*
??????????????????執(zhí)行多重Linq查詢
???
??????????????????檢索所在城市為中國(guó),?且訂單日期為2007年以后的所有記錄
??????????????????查詢結(jié)果是一個(gè)匿名類型的數(shù)組
??????????????????其中包含客戶名,?訂單號(hào),?訂單日期,?訂單名四個(gè)字段
??????????????*/
??????????????var?someCustomers?=?from?c?in?customers
??????????????????????????????????where?c.City?==?"China"
??????????????????????????????????from?o?in?c.Orders
??????????????????????????????????where?o.OrderDate.Year?>=?2007
??????????????????????????????????select?new?{?c.Name,?o.OrderNo,?o.OrderDate,?o.OrderName?};
???
???
??????????????foreach?(var?customer?in?someCustomers)
??????????????{
??????????????????Console.WriteLine(
??????????????????????customer.Name?+?",?"?+?customer.OrderName?+?",??"?+
??????????????????????customer.OrderDate.ToString("D")
??????????????????);
??????????????}
??????????}
??????}
?
????? 從上面的例子中,我們可以看到Linq查詢的強(qiáng)大特性,它允許我們進(jìn)行簡(jiǎn)單查詢,或者進(jìn)行更為復(fù)雜的多重連接查詢。且查詢的結(jié)果還可以是自定義的匿名類型。
?
?轉(zhuǎn)載于:https://www.cnblogs.com/ccsonline/archive/2007/11/19/964127.html
總結(jié)
以上是生活随笔為你收集整理的C# 3.X -- the newest features的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 求推荐一个做顶墙门柜一体化装修的大品牌?
- 下一篇: 项目管理九大知识体系: