為什么要有泛型?
? 既然不知道,那我們就給Book定義一種排序規(guī)則(按價(jià)格排序),我們聲明一個(gè)用于比較的接口:
? 請(qǐng)大家思考一個(gè)問題:由你來(lái)實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的冒泡排序算法。假設(shè)沒有使用泛型的經(jīng)驗(yàn)??赡軙?huì)毫不猶豫的寫出下面代碼:
public class SortHelper { //參數(shù)為int數(shù)組的冒泡排序 public void BubbleSort(int[] array) { int length = array.Length; for (int i = 0; i <= length - 2; i++) { for (int j = length - 1; j >= 1; j--) { //對(duì)兩個(gè)元素進(jìn)行交換 if (array[j] < array[j - 1]) { int temp = array[j]; array[j] = array[j - 1]; array[j - 1] = temp; } } } } }? 如今通過對(duì)這個(gè)程序進(jìn)行一個(gè)簡(jiǎn)單的測(cè)試:
static void Main(string[] args) { #region 沒有泛型前的演示 SortHelper sorter = new SortHelper(); int[] arrayInt = { 8, 1, 4, 7, 3 }; //對(duì)int數(shù)組排序 sorter.BubbleSort(arrayInt); foreach (int i in arrayInt) { Console.Write("{0} ", i); } Console.ReadLine(); #endregion }? 我們發(fā)現(xiàn)它執(zhí)行良好,欣喜的覺得這便是最好的解決方式了。直到不久后,須要對(duì)一個(gè)byte類型的數(shù)組進(jìn)行排序。而上面的排序算法僅僅能接受一個(gè)int類型的數(shù)組。C#是一個(gè)強(qiáng)類型的語(yǔ)言。無(wú)法在一個(gè)接受int數(shù)組類型的地方傳入一個(gè)byte數(shù)組。只是沒關(guān)系,如今看來(lái)最快的解決方法是把代碼復(fù)制一遍,然后將方法的簽名改一下:
public class SortHelper { //參數(shù)為byte數(shù)組的冒泡排序 public void BubbleSort(byte[] array) { int length = array.Length; for (int i = 0; i <= length - 2; i++) { for (int j = length - 1; j >= 1; j--) { //對(duì)兩個(gè)元素進(jìn)行交換 if (array[j] < array[j - 1]) { byte temp = array[j]; array[j] = array[j - 1]; array[j - 1] = temp; } } } } }? 好了,再一次解決這個(gè)問題??赏ㄟ^認(rèn)證觀察我們發(fā)現(xiàn),這兩個(gè)方法除了傳入的參數(shù)類型不同外。方法的實(shí)現(xiàn)非常相似,是能夠進(jìn)行進(jìn)一步抽象的。于是我們思考,為什么在定義參數(shù)的時(shí)候不用一個(gè)占位符T取代呢?T是Type的縮寫。能夠代表不論什么類型,這樣就能夠屏蔽兩個(gè)方法簽名的差異: ? ?
public class SortHelper<T> { //參數(shù)為T的冒泡排序 public void BubbleSort(T[] array) { int length = array.Length; for (int i = 0; i <= length - 2; i++) { for (int j = length - 1; j >= 1; j--) { //對(duì)兩個(gè)元素進(jìn)行交換 if (array[j] < array[j - 1]) { T temp = array[j]; array[j] = array[j - 1]; array[j - 1] = temp; } } } }? 通過代碼我們能夠發(fā)現(xiàn),使用泛型極大的降低了反復(fù)代碼,使代碼更加清爽。
泛型類就類似于一個(gè)模板,能夠再須要時(shí)為這個(gè)模板傳入不論什么須要的類型。如今更專業(yè)些,為占位符T起一個(gè)正式的名稱。在.Net中叫做“類型參數(shù)”。
類型參數(shù)約束? 實(shí)際上,如果執(zhí)行上面的代碼就會(huì)發(fā)現(xiàn),它連編譯都通只是去,為什么呢?考慮這樣一個(gè)問題:如果我們自己定義一個(gè)類型。名字叫做Book,它包括兩個(gè)字段:一個(gè)是int類型的Price代表書的價(jià)格;一個(gè)是string類型的Title,代表書的標(biāo)題:
public class Book { //價(jià)格字段 private int price; //標(biāo)題字段 private string title; //構(gòu)造函數(shù) public Book() { } public Book(int price, string title) { this.price = price; this.title = title; } //價(jià)格屬性 public int Price { get { return this.price; } } //標(biāo)題屬性 public string Titie { get { return this.title; } } }? 如今創(chuàng)建一個(gè)Book類型的數(shù)組,然后使用上面定義的泛型類對(duì)它進(jìn)行排序,代碼應(yīng)該像以下這樣:
Book[] bookArray = new Book[2]; Book book1 = new Book(30, "HTML5解析"); Book book2 = new Book(21, "JavaScript實(shí)戰(zhàn)"); bookArray[0] = book1; bookArray[1] = book2; SortHelper<Book> sorterGeneric = new SortHelper<Book>(); sorterGeneric.BubbleSort(bookArray); foreach (Book b in bookArray) { Console.WriteLine("Price:{0}", b.Price); Console.WriteLine("Title:{0}", b.Titie); }? 這時(shí)問題來(lái)了。既然是排序。就免不了比較大小,那么如今請(qǐng)問:book1和book2誰(shuí)比較大?張三能夠說(shuō)book1大,由于它的Price是30,;而李四能夠說(shuō)book2大,由于它的Title是“J”開頭的,比book1的“H”靠后。說(shuō)了半天,問題在于不確定按什么規(guī)則排序。
? 既然不知道,那我們就給Book定義一種排序規(guī)則(按價(jià)格排序),我們聲明一個(gè)用于比較的接口:
public interface IComparable { int CompareTo(object obj); }? 讓Book類型實(shí)現(xiàn)這個(gè)接口:
public class Book : IComparable ? ? { ? ? ? ? //CODE:上面的實(shí)現(xiàn)略 ? ? ? ? public int CompareTo(object obj) ? ? ? ? { ? ? ? ? ? ? Book book2 = (Book)obj; ? ? ? ? ? ? return this.Price.CompareTo(book2.Price); ? ? ? ? } ? ? }? 既然我們?nèi)缃褚呀?jīng)讓Book類實(shí)現(xiàn)了IComparable接口,那么泛型類應(yīng)該可以工作了吧?不行的,還要記得,泛型類是一個(gè)模板類。它對(duì)在運(yùn)行時(shí)傳遞的類型參數(shù)是一無(wú)所知的。也不會(huì)做不論什么的推測(cè)。所以須要我們告訴泛型類SortHelper<T>,它所接受的T類型參數(shù)必須可以進(jìn)行比較,也就是說(shuō)必須實(shí)現(xiàn)IComparable接口。我們把對(duì)T進(jìn)行約束這樣的行為稱:泛型參數(shù)約束。
? 為了要求類型參數(shù)T必須實(shí)現(xiàn)IComparable接口,須要像以下這樣又一次定義:
public class SortHelper<T> where T : IComparable { //參數(shù)為T的冒泡排序 public void BubbleSort(T[] array) { int length = array.Length; for (int i = 0; i <= length - 2; i++) { for (int j = length - 1; j >= 1; j--) { //對(duì)兩個(gè)元素進(jìn)行交換 if (array[j].CompareTo(array[j - 1]) < 0) { T temp = array[j]; array[j] = array[j - 1]; array[j - 1] = temp; } } } } }? 上面的定義說(shuō)明了類型參數(shù)T必須實(shí)現(xiàn)IComparable接口。否則將無(wú)法通過編譯。由于如今T已經(jīng)實(shí)現(xiàn)了IComparable接口,而數(shù)組array中的成員是T的實(shí)例。所以當(dāng)在array[i]后面點(diǎn)擊小數(shù)點(diǎn)“.”時(shí),VS能夠智能提醒出T是IComparable的成員,也就是CompareTo()方法。
本文摘自 :https://blog.51cto.com/u