c#泛型
寫在前面:此隨筆僅僅是作為個人學習總結,有不對的地方,請各位前輩指正O(∩_∩)O........
一: 什麽是泛型
泛型是c#2.0之後新特性,是一種語法糖.將大量的安全檢查從執行期轉移至了編譯期,使類型參數化.大至思想就是編譯時期確定其類型,延遲思想.
二: 使用泛型
1: 泛型的出現,提高了性能,那麽沒有泛型之前是一個什麽樣子呢?
舉個例子:
比如,我們要分別輸出一個數字和字符串,我們需要像這樣寫:
/// <summary> /// 打印數字 /// </summary> /// <param name="i"></param>public void PrintInt(int i) { Console.WriteLine("this is a method print number: {0},this type is {1}", i, i.GetType()); } /// <summary> /// 打印字符串 /// </summary> /// <param name="s"></param> public void PrintString(strings) { Console.WriteLine("this is a method print string: {0},this type is {1}",s,s.GetType()); }
可以看到上面兩個方法內部都是基本上相同的.那聰明的程序員們就思考怎麽可以優化上面的代碼.我們可以知道object是所有的父類,那麽就有了下面這一個優化之後的代碼:
public void PrintObject(object o) { Console.WriteLine("this is a method print object: {0},this type is {1}", o,o.GetType()); }
這樣我們就把兩個方法優化成了一個方法,達到了一樣的目的.接下來問題又來了,現在這樣的寫法,就又存在了一個問題,就是裝箱和拆箱的問題,一次兩個裝箱拆箱我們似乎可以忽略,但是大量的進行裝箱和拆箱那就太損失性能啦.
由於這樣那樣的問題,聰明的程序員就思考,怎麽能夠避免裝箱拆箱問題,又能將代碼變得簡單可讀的,就這樣泛型就隨之產生啦.來看看有了泛型之後上面的代碼又會變成什麽樣呢?
/// <summary> /// 泛型方法 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="param"></param> public void PrintGenerics<T>(T param) { Console.WriteLine("this is a generics method print param: {0},this type is {1}", param,param.GetType()); } //使用 common.PrintGenerics<int>(1);
common.PrintGenerics(1);
這樣就是一個泛型方法了.現在有幾個疑問就是:
a: T是一個什麽東西呢,以前都沒有見過?
答: 從文檔註釋,對T的解釋,T是一個類型參數,需要我們傳入具體的類型實參,T實際上是一個占位符,在編譯之後就變成了 `1這樣一個占位符.
b: 在調用的時候為什麽可以省略<int>呢?
答: 編譯器會根據傳入的參數,來推斷出具體的類型
c: 這種方式為什麽就比通過object來輸出好呢?
答: 從上面的解釋可以知道object是存在裝箱和拆箱問題的,會損耗性能.而泛型就不存在裝箱和拆箱的問題,因為從前面可以知道泛型是在編譯的時候才知道類型,實際上編譯器在我們不知道的時候根據他的類型創建了相應數據類型的副本方法,比如:
common.PrintGenerics<int>(1); //創建的副本方法類似於 public void PrintInt(int i) { Console.WriteLine("this is a method print number: {0},this type is {1}", i, i.GetType()); }
這樣就不存在值類型到引用類型的轉換.
2: 泛型還有哪些應用呢?
泛型類,泛型接口,泛型方法,泛型返回,泛型約束
2.1: 泛型約束:
泛型約束是個什麽東西呢?大概就是讓參數滿足它的條件(2333,解釋不來 =_=||)
就比如:
common.PrintGenerics<Person>(new Person());
我們此時的參數是一個person對象,那麽我們想輸出person的名字,但是我們發現這樣是沒有出現param.Name的.
這是為什麽呢?
因為此時我們的參數沒有添加約束,就相當於是一個object,那object裏面有name屬性嗎?很顯然是沒有的.舉個例子:就像我們讓一個"str"字符串輸出它的name屬性,是不現實的,因為沒有.
這個時候我們的約束就該上場啦
public void PrintGenericsPerson<T>(T p) where T: Person { Console.WriteLine("my name is :"+p.Name); }
泛型約束通過where來實現.
那麽疑問又來了:
a: 約束後的效果是什麽樣呢?
答: 現在我們就只能person類型以及它的子類型來作為參數啦.
b: 這樣寫和直接規定它的參數類型為person有什麽區別嗎?
答: 個人認為一般在確定是person類型的時候,就不會在傳入其子類型作為參數了,在做架構方面可能非常有用(個人理解不是很透徹)
c: 還有其他的約束嗎?
答: class: 表示約束為引用類型(此時傳一個數字就會出錯). struct: 表示約束為值類型(DateTime為值類型). new(): 表示約束參數要有無參數的構造函數.等等
2.2: 泛型的靜態成員變量
靜態成員在相同的封閉類間共享.不同的封閉類間不共享
開放類型:泛型類型沒有指定具體的數據類型.
封閉類型:泛型類型指定了具體的數據類型.
2.3: 泛型方法的重載
a: 是在實例方法被調用的時候檢查重載是否混淆,而不是在泛型類本身編譯時檢查
b: 當一般方法與泛型方法具有相同的簽名時,會覆蓋掉泛型方法,而使用一般的方法.
c#泛型