C#學習筆記—C#2.0範型

來源:互聯網
上載者:User
3.範型的執行個體化
跟不是範型的類型類似,編譯後的範型也表現為IL指令和中繼資料.當然範型也會編碼已存在和使用的型別參數.
在構造範型類型,比如stack<int>的執行個體在程式中被構造時,.NET的CLR JIT編譯器將會把IL指令和中繼資料轉化成本地代碼,在這個過程中將會用實際類型替換型別參數.以後對該構造範型類型的引用將會使用同一份本地代碼.從範型類型建立一個特定的構造範型類型的過程叫做範型類型的執行個體化(Generic Type Instantiation).
.NET運行時會為每個用實值型別進行的範型的執行個體化建立一份特定的本地代碼拷貝,但是用參考型別進行的範型的執行個體化會共用一份本地代碼(因為在本地代碼層次,引用是具有同樣表現形式的指標).
4.約束
如果想用type parameters 調用某些方法會出現什麼情況那?public class Dictionary<K,V>

{

    public void Add(K key, V value)

    {

        

        if (key.CompareTo(x) < 0) {}   // Error, no CompareTo method

        

    }

}

因為key被定義為可以為任意類型,所以key只能調用object聲明的方法成員,比如Equals, GetHashCode和ToString,當然可以把key轉化為有CompareTo定義的類型,比如轉化為IComparable類型.

public class Dictionary<K,V>

{

    public void Add(K key, V value)

    {

        

        if (((IComparable)key).CompareTo(x) < 0) {}

        

    }

}

儘管這個解決方案可用,但是會引起運行時檢查,並把錯誤延遲到運行時,拋出InvalidCastException 異常.
為了支援更強的編譯時間檢查和減少類型轉化帶來的開銷,C#允許為每個型別參數提供一個可選的約束(Constraints)列表.Constraints的定義以where+型別參數+類或者介面類型的類表[+構造器約束new()].
對於範型Dictionary<K,V>為了確保其中的keys實現IComparable介面,可以對K做一個約束.

public class Dictionary<K,V> where K: IComparable

{

    public void Add(K key, V value)

    {

        

        if (key.CompareTo(x) < 0) {}

        

    }

}

對於一個給定的型別參數,可以指定多個Interface做為約束,但是只能指定至多一個類做為約束,這個跟繼承的規則是一樣的,每個有約束條件的型別參數有一個單獨的where子句.構造器約束new()規定被用做一個型別參數的類型argument必須有一個public類型的,無參的建構函式,這樣就允許用new ()的方式構造指定類型的執行個體.
5.範型方法
在某些情況下,並不需要整個類是範型,而只需要某個類的方法成員是範型的.這經常發生在當把一個範型類型做為一個方法的參數時.比如Stack<T>這個範型,當想把一組中的多個值一次性壓入棧的時候,寫一個方法把這些值在一個方法調用時實現這個功能是比較方便的.對於一個給定的構造類型,比如Stack<int>,這個方法可以用如下方式定義:

void PushMultiple(Stack<int> stack, params int[] values) {

    foreach (int value in values) stack.Push(value);

}

這個方法可以將多個int值壓入棧.但是這個方法用於特定的構造類型,為了讓它跟Stack<T>協同工作,必須定義範型方法.範型方法可以在方法名後面帶多個型別參數,這些型別參數可以在參數列表,傳回型別和方法體中,一個範型PushMultiple 可以像如下定義:void PushMultiple<T>(Stack<T> stack, params T[] values) {

    foreach (T value in values) stack.Push(value);

}

調用方式如下:Stack<int> stack = new Stack<int>();

PushMultiple<int>(stack, 1, 2, 3, 4);

這樣這個方法可以複用,但是有個不方便的地方就是每次調用都要指定<int>,這有些不太方便,但是在很多情況下,編譯器能夠根據其他參數的類型推斷出該方法正確的參數類型,這個過程成為類型推斷(type inferencing),比如前一個例子,由於第一個參數是Stack<int>類型的,後面的參數也是int的,所以可以推斷出參數類型一定是int,所以這個方法也可以不指定型別參數,調用方式如下:Stack<int> stack = new Stack<int>();

PushMultiple(stack, 1, 2, 3, 4);

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.