• 當前位置:首頁 > IT技術 > Windows編程 > 正文

    深入理解C#中的泛型(一)
    2021-08-06 19:48:40

    為什么要有泛型?

    ? 請大家思考一個問題:由你來實現一個最簡單的冒泡排序算法。假設沒有使用泛型的經驗??赡軙敛华q豫的寫出下面代碼:

    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()方法。

    本文摘自 :https://blog.51cto.com/u

    開通會員,享受整站包年服務
    国产呦精品一区二区三区网站|久久www免费人咸|精品无码人妻一区二区|久99久热只有精品国产15|中文字幕亚洲无线码