深入理解C#中的泛型(一)

來源:互聯網
上載者:User
為什麼要有泛型。

  請大家思考一個問題:由你來實現一個最簡單的冒泡排序演算法,如果沒有使用泛型的經驗,可能會毫不猶豫的寫出以下代碼:

public class SortHelper    {        //參數為int數組的冒泡排序        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--)                {                    //對兩個元素進行交換                    if (array[j] < array[j - 1])                    {                        int temp = array[j];                        array[j] = array[j - 1];                        array[j - 1] = temp;                    }                }            }        }    }
  現在通過對這個程式進行一個簡單的測試:
      static void Main(string[] args)        {            #region  沒有泛型前的示範            SortHelper sorter = new SortHelper();            int[] arrayInt = { 8, 1, 4, 7, 3 };            //對int數組排序            sorter.BubbleSort(arrayInt);            foreach (int i in arrayInt)            {                Console.Write("{0} ", i);            }            Console.ReadLine();            #endregion        }
  我們發現它運行良好,欣喜的認為這便是最好的解決方案了。直到不久後,需要對一個byte類型的數組進行排序,而上面的排序演算法只能接受一個int類型的數組。C#是一個強型別的語言,無法在一個接受int數群組類型的地方傳入一個byte數組。不過沒關係,現在看來最快的解決方案是把代碼複製一遍,然後將方法的簽名改一下:
 public class SortHelper    {        //參數為byte數組的冒泡排序        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--)                {                    //對兩個元素進行交換                    if (array[j] < array[j - 1])                    {                        byte temp = array[j];                        array[j] = array[j - 1];                        array[j - 1] = temp;                    }                }            }        }    }
  好了,再一次解決問題。可通過認證觀察我們發現,這兩個方法除了傳入的參數類型不同外,方法的實現很相似,是可以進行進一步抽象的,於是我們思考,為什麼在定義參數的時候不用一個預留位置T代替呢。T是Type的縮寫,可以代表任何類型,這樣就可以屏蔽兩個方法簽名的差異:    
   public class SortHelper<T>    {        //參數為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--)                {                    //對兩個元素進行交換                    if (array[j] < array[j - 1])                    {                        T temp = array[j];                        array[j] = array[j - 1];                        array[j - 1] = temp;                    }                }            }        }
  通過代碼我們可以發現,使用泛型極大的減少了重複代碼,使代碼更加清爽。泛型類就類似於一個模板,可以再需要時為這個模板傳入任何需要的類型。現在更專業些,為預留位置T起一個正式的名稱,在.Net中叫做“型別參數”。 型別參數約束

  實際上,如果運行上面的代碼就會發現,它連編譯都通不過去,為什麼呢。考慮這樣一個問題:假設我們自訂一個類型,名字叫做Book,它包含兩個欄位:一個是int類型的Price代表書的價格;一個是string類型的Title,代表書的標題:

public class Book     {        //價格欄位        private int price;        //標題欄位        private string title;        //建構函式        public Book() { }        public Book(int price, string title)        {            this.price = price;            this.title = title;        }        //價格屬性        public int Price        {            get { return this.price; }        }        //標題屬性        public string Titie        {            get { return this.title; }        }    }
  現在建立一個Book類型的數組,然後使用上面定義的泛型類對它進行排序,代碼應該像下面這樣:
            Book[] bookArray = new Book[2];            Book book1 = new Book(30, "HTML5解析");            Book book2 = new Book(21, "JavaScript實戰");            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);            }
  這時問題來了,既然是排序,就免不了比較大小,那麼現在請問:book1和book2誰比較大。張三可以說book1大,因為它的Price是30,;而李四可以說book2大,因為它的Title是“J”開頭的,比book1的“H”靠後。說了半天,問題在於不確定按什麼規則排序。
  既然不知道,那我們就給Book定義一種定序(按價格排序),我們聲明一個用於比較的介面:
 public interface IComparable    {        int CompareTo(object obj);    }
  讓Book類型實現這個介面:
public class Book : IComparable    {        //CODE:上面的實現略        public int CompareTo(object obj)        {            Book book2 = (Book)obj;            return this.Price.CompareTo(book2.Price);        }    }
  既然我們現在已經讓Book類實現了IComparable介面,那麼泛型類應該可以工作了吧。不行的,還要記得,泛型類是一個模板類,它對在執行時傳遞的型別參數是一無所知的,也不會做任何的猜測,所以需要我們告訴泛型類SortHelper<T>,它所接受的T型別參數必須能夠進行比較,也就是說必須實現IComparable介面,我們把對T進行約束這種行為稱:泛型參數約束。

  為了要求型別參數T必須實現IComparable介面,需要像下面這樣重新定義:

public class SortHelper<T> where T : IComparable    {        //參數為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--)                {                    //對兩個元素進行交換                    if (array[j].CompareTo(array[j - 1]) < 0)                    {                        T temp = array[j];                        array[j] = array[j - 1];                        array[j - 1] = temp;                    }                }            }        }    }
  上面的定義說明了型別參數T必須實現IComparable介面,否則將無法通過編譯。因為現在T已經實現了IComparable介面,而數組array中的成員是T的執行個體,所以當在array[i]後面點擊小數點“.”時,VS可以智能提醒出T是IComparable的成員,也就是CompareTo()方法。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.