轉(zhuǎn) C# 2.0 泛型(Generics) 泛型是CLR 2.0中引入的最重要的新特性,,使得可以在類,、方法中對(duì)使用的類型進(jìn)行參數(shù)化。 例如,,這里定義了一個(gè)泛型類:
使用的時(shí)候:
泛型的好處
泛型方法、泛型委托,、泛型接口 除了泛型類之外,,還有泛型方法、泛型委托,、泛型接口: //泛型委托 public static delegate T1 MyDelegate MyDelegate String str1 = 'a';String str2 = 'b';Swap
泛型約束(constraints) 可以給泛型的類型參數(shù)上加約束,,可以要求這些類型參數(shù)滿足一定的條件
這些約束,,可以同時(shí)一起使用:
default 關(guān)鍵字 這個(gè)關(guān)鍵可以使用在類型參數(shù)上: default(T); 對(duì)于值類型,,返回0,引用類型,,返回null,,對(duì)于結(jié)構(gòu)類型,會(huì)返回一個(gè)成員值全部為0的結(jié)構(gòu)實(shí)例,。 迭代器(iterator) 可以在不實(shí)現(xiàn)IEnumerable就能使用foreach語句,,在編譯器碰到y(tǒng)ield return時(shí),,它會(huì)自動(dòng)生成IEnumerable 接口的方法,。在實(shí)現(xiàn)迭代器的方法或?qū)傩灾校祷仡愋捅仨毷荌Enumerable, IEnumerator, IEnumerable public System.Collections.IEnumerator GetEnumerator() { yield return -1; for (int i = 1; i < max;="" i++)="">yield return i; } } 可空類型(Nullable Type) 可空類型System.Nullable int? num = null; if (num.HasValue == true) { System.Console.WriteLine('num = ' + num.Value); } else { System.Console.WriteLine('num = Null'); } 如果HasValue為false,,那么在使用value值的時(shí)候會(huì)拋出異常。把一個(gè)Nullable的變量x賦值給一個(gè)非Nullable的變量y可以這么寫: int y = x ?? -1; 匿名方法(Anonymous Method) 在C#2.0之前,,給只能用一個(gè)已經(jīng)申明好的方法去創(chuàng)建一個(gè)委托,。有了匿名方法后,可以在創(chuàng)建委托的時(shí)候直接傳一個(gè)代碼塊過去,。 delegate void Del(int x); Del d = delegate(int k) { /* ... */ }; System.Threading.Thread t1 = new System.Threading.Thread (delegate() { System.Console.Write('Hello, '); } ); 委托語法的簡化// C# 1.0的寫法 ThreadStart ts1 = new ThreadStart(Method1); // C# 2.0可以這么寫 ThreadStart ts2 = Method1; 委托的協(xié)變和逆變(covariance and contravariance) 有下面的兩個(gè)類: class Parent { } class Child: Parent { } 然后看下面的兩個(gè)委托: public delegate Parent DelgParent(); public delegate Child DelgChild(); public static Parent Method1() { return null; } public static Child Method2() { return null; } static void Main() { DelgParent del1= Method1; DelgChild del2= Method2; del1 = del2; } 注意上面的,,DelgParent 和DelgChild 是完全不同的類型,他們之間本身沒有任何的繼承關(guān)系,,所以理論上來說他們是不能相互賦值的。但是因?yàn)閰f(xié)變的關(guān)系,,使得我們可以把DelgChild類型的委托賦值給DelgParent 類型的委托。協(xié)變針對(duì)委托的返回值,,逆變針對(duì)參數(shù),原理是一樣的,。 部分類(partial) 在申明一個(gè)類,、結(jié)構(gòu)或者接口的時(shí)候,,用partial關(guān)鍵字,,可以讓源代碼分布在不同的文件中。我覺得這個(gè)東西完全是為了照顧Asp.net代碼分離而引入的功能,,真沒什么太大的實(shí)際用處,。微軟說在一些大工程中可以把類分開在不同的文件中讓不同的人去實(shí)現(xiàn),方便團(tuán)隊(duì)協(xié)作,,這個(gè)我覺得純屬胡扯,。 部分類僅是編譯器提供的功能,在編譯的時(shí)候會(huì)把partial關(guān)鍵字定義的類和在一起去編譯,,和CRL沒什么關(guān)系,。 靜態(tài)類(static class) 靜態(tài)類就一個(gè)只能有靜態(tài)成員的類,用static關(guān)鍵字對(duì)類進(jìn)行標(biāo)示,,靜態(tài)類不能被實(shí)例化。靜態(tài)類理論上相當(dāng)于一個(gè)只有靜態(tài)成員并且構(gòu)造函數(shù)為私有的普通類,,靜態(tài)類相對(duì)來說的好處就是,,編譯器能夠保證靜態(tài)類不會(huì)添加任何非靜態(tài)成員,。 global:: 這個(gè)代表了全局命名空間(最上層的命名空間),也就是任何一個(gè)程序的默認(rèn)命名空間,。 class TestApp { public class System { } const int Console = 7; static void Main() { //用這個(gè)訪問就會(huì)出錯(cuò),,System和Console都被占用了 //Console.WriteLine(number); global::System.Console.WriteLine(number); } } extern alias 用來消除不同程序集中類名重復(fù)的沖突,這樣可以引用同一個(gè)程序集的不同版本,,也就是說在編譯的時(shí)候,,提供了一個(gè)將有沖突的程序集進(jìn)行區(qū)分的手段。 在編譯的時(shí)候,,使用命令行參數(shù)來指明alias,,例如: /r:aliasName=assembly1.dll 在Visual Studio里面,在被引用的程序集的屬性里面可以指定Alias的值,,默認(rèn)是global,。 然后在代碼里面就可以使用了: extern alias aliasName; //這行需要在using這些語句的前面 using System; using System.Collections.Generic; using System.Text; using aliasName.XXX; 屬性Accessor訪問控制 public virtual int TestProperty { protected set { } get { return 0; } } 友元程序集(Friend Assembly) 可以讓其它程序集訪問自己的internal成員(private的還是不行),使用Attributes來實(shí)現(xiàn),,例如: [assembly:InternalsVisibleTo('cs_friend_assemblies_2')] 注意這個(gè)作用范圍是整個(gè)程序集,。 fixed關(guān)鍵字 可以使用fixed關(guān)鍵字來創(chuàng)建固定長度的數(shù)組,但是數(shù)組只能是bool, byte, char, short, int, long, sbyte, ushort, uint, ulong, float, double中的一種,。 這主要是為了更好的處理一些非托管的代碼,。比如下面的這個(gè)結(jié)構(gòu)體: public struct MyArray { public fixed char pathName[128]; } 如果不用fixed的話,無法預(yù)先占住128個(gè)char的空間,,使用fixed后可以很好的和非托管代碼進(jìn)行交互,。 volatile關(guān)鍵字 用來表示相關(guān)的字可能被多個(gè)線程同時(shí)訪問,編譯器不會(huì)對(duì)相應(yīng)的值做針對(duì)單線程下的優(yōu)化,,保證相關(guān)的值在任何時(shí)候訪問都是最新的,。 #pragma warning 用來取消或者添加編譯時(shí)的警告信息。每個(gè)警告信息都會(huì)有個(gè)編號(hào),,如果warning CS01016之類的,,使用的時(shí)候取CS后面的那個(gè)數(shù)字,,例如: #pragma warning disable 414, 3021 這樣CS414和CS3021的警告信息就都不會(huì)顯示了。 C# 3.0 類型推斷 申明變量的時(shí)候,,可以不用直指定類型: 類型推斷也支持?jǐn)?shù)組: 擴(kuò)展方法 擴(kuò)展方法必須被定義在靜態(tài)類中,,并且必須是非泛型、非嵌套的靜態(tài)類,。例如: 上面一個(gè)是給string類型的對(duì)象添加了一個(gè)方法,,另一個(gè)是給所有類型的數(shù)組添加了一個(gè)方法,方法有兩個(gè)整型參數(shù),。 擴(kuò)展方法只在當(dāng)前的命名空間類有效,,如果所在命名空間被其它命名空間import引用了,那么在其它命名空間中也有效,。擴(kuò)展方法的優(yōu)先級(jí)低于其它的常規(guī)方法,,也就是說如果擴(kuò)展方法與其它的方法相同,那么擴(kuò)展方法不會(huì)被調(diào)用,。 Lamda表達(dá)式 可以看成是對(duì)匿名方法的一個(gè)語法上的簡化,,但是λ表達(dá)式同時(shí)可以裝換為表達(dá)式樹類型。 對(duì)象和集合的初始化 匿名類型 自動(dòng)屬性 會(huì)自動(dòng)生成一個(gè)后臺(tái)的私有變量 查詢表達(dá)式 這個(gè)其實(shí)就是擴(kuò)展方法的運(yùn)用,,編譯器提供了相關(guān)的語法便利,,下面兩端代碼是等價(jià)的: 表達(dá)式樹 C# 4.0 協(xié)變和逆變 這個(gè)在C#2.0中就已經(jīng)支持委托的協(xié)變和逆變了,C#4.0開始支持針對(duì)泛型接口的協(xié)變和逆變: 協(xié)變和逆變僅針對(duì)引用類型,。 動(dòng)態(tài)綁定 看例子: 可選參數(shù),命名參數(shù) 這樣,,最后一個(gè)參數(shù)不給的話默認(rèn)值就是1,,提供這個(gè)特性可以免去寫一些重載方法的麻煩。 調(diào)用方法的時(shí)候,,可以指定參數(shù)的名字來給值,,不用按照方法參數(shù)的順序來制定參數(shù)值: 1. 異步編程 在.Net 4.5中,通過async和await兩個(gè)關(guān)鍵字,,引入了一種新的基于任務(wù)的異步編程模型(TAP),。在這種方式下,可以通過類似同步方式編寫異步代碼,,極大簡化了異步編程模型。如下式一個(gè)簡單的實(shí)例: static async void DownloadStringAsync2(Uri uri) 而之前的方式是這樣的: static void DownloadStringAsync(Uri uri) 也許前面這個(gè)例子不足以體現(xiàn)async和await帶來的優(yōu)越性,,下面這個(gè)例子就明顯多了: public void CopyToAsyncTheHardWay(Stream source, Stream destination) 關(guān)于基于任務(wù)的異步編程模型需要介紹的地方還比較多,,不是一兩句能說完的,,有空的話后面再專門寫篇文章來詳細(xì)介紹下。另外也可參看微軟的官方網(wǎng)站:Visual Studio Asynchronous Programming,,其官方文檔Task-Based Asynchronous Pattern Overview介紹的非常詳細(xì),, VisualStudio中自帶的CSharp Language Specification中也有一些說明。 2. 調(diào)用方信息 很多時(shí)候,,我們需要在運(yùn)行過程中記錄一些調(diào)測(cè)的日志信息,,如下所示: public void DoProcessing() 為了調(diào)測(cè)方便,除了事件信息外,,我們往往還需要知道發(fā)生該事件的代碼位置以及調(diào)用棧信息,。在C++中,我們可以通過定義一個(gè)宏,,然后再宏中通過__FILE__和__LINE__來獲取當(dāng)前代碼的位置,,但C#并不支持宏,往往只能通過StackTrace來實(shí)現(xiàn)這一功能,,但StackTrace卻有不是很靠譜,,常常獲取不了我們所要的結(jié)果。 針對(duì)這個(gè)問題,,在.Net 4.5中引入了三個(gè)Attribute:CallerMemberName,、CallerFilePath和CallerLineNumber。在編譯器的配合下,,分別可以獲取到調(diào)用函數(shù)(準(zhǔn)確講應(yīng)該是成員)名稱,,調(diào)用文件及調(diào)用行號(hào)。上面的TraceMessage函數(shù)可以實(shí)現(xiàn)如下: public void TraceMessage(string message, 另外,,在構(gòu)造函數(shù),,析構(gòu)函數(shù)、屬性等特殊的地方調(diào)用CallerMemberName屬性所標(biāo)記的函數(shù)時(shí),,獲取的值有所不同,,其取值如下表所示: 調(diào)用的地方 CallerMemberName獲取的結(jié)果 方法、屬性或事件 方法,,屬性或事件的名稱 構(gòu)造函數(shù) 字符串 '.ctor' 靜態(tài)構(gòu)造函數(shù) 字符串 '.cctor' 析構(gòu)函數(shù) 該字符串 'Finalize' 用戶定義的運(yùn)算符或轉(zhuǎn)換 生成的名稱成員,,例如, 'op_Addition',。 特性構(gòu)造函數(shù) 特性所應(yīng)用的成員的名稱 例如,,對(duì)于在屬性中調(diào)用CallerMemberName所標(biāo)記的函數(shù)即可獲取屬性名稱,通過這種方式可以簡化 INotifyPropertyChanged 接口的實(shí)現(xiàn),。 1,、自動(dòng)屬性的增強(qiáng) 1.1、自動(dòng)屬性初始化 (Initializers for auto-properties) C#4.0下的果斷實(shí)現(xiàn)不了的。 C#6.0中自動(dòng)屬性的初始化方式 只要接觸過C#的肯定都會(huì)喜歡這種方式,。真是簡潔方便呀,。 1.2、只讀屬性初始化Getter-only auto-properties 先來看一下我們之前使用的方式吧 再來看一下C#6.0中 和第一條自動(dòng)屬性初始化使用方式一致,。 2,、Expression bodied function members 2.1 用Lambda作為函數(shù)體Expression bodies on method-like members 再來舉一個(gè)簡單的例子:一個(gè)沒有返回值的函數(shù) 2.2、Lambda表達(dá)式用作屬性Expression bodies on property-like function members 現(xiàn)在C#6中 3,、引用靜態(tài)類Using Static 在Using中可以指定一個(gè)靜態(tài)類,,然后可以在隨后的代碼中直接使用靜態(tài)的成員 4、空值判斷Null-conditional operators 直接來看代碼和運(yùn)行結(jié)果 通過結(jié)果可以發(fā)現(xiàn)返回的都為null,再也不像以前那樣繁瑣的判斷null勒,。 5,、字符串嵌入值 在字符串中嵌入值 之前一直使用的方式是 現(xiàn)在我們可以簡單的通過如下的方式進(jìn)行拼接 6、nameof表達(dá)式nameof expressions 在方法參數(shù)檢查時(shí),,你可能經(jīng)??吹竭@樣的代碼(之前用的少,這次也算學(xué)到了) 里面有那個(gè)customer是我們手寫的字符串,,在給customer改名時(shí),,很容易把下面的那個(gè)字符串忘掉,C#6.0 nameof幫我們解決了這個(gè)問題,,看看新寫法 7,、帶索引的對(duì)象初始化器Index initializers 直接通過索引進(jìn)行對(duì)象的初始化,原來真的可以實(shí)現(xiàn) 通過這種方式可以發(fā)現(xiàn)字典中只有三個(gè)元素,,所以也就只有這三個(gè)索引可以訪問額,,其他類型的對(duì)象和集合也是可以通過這種方式進(jìn)行初始化的,在此就不進(jìn)行一一列舉了,。 8,、異常過濾器 (Exception filters) 先來看一個(gè)移植過來的方法 在微軟的文檔中還給出了另一種用法,這個(gè)異常會(huì)在日志記錄失敗時(shí)拋給上一層調(diào)用者 9,、catch和finally 中的 await —— Await in catch and finally blocks 在C#5.0中,,await關(guān)鍵字是不能出現(xiàn)在catch和finnaly塊中的。而在6.0中 10,、無參數(shù)的結(jié)構(gòu)體構(gòu)造函數(shù)—— Parameterless constructors in structs |
|