1. 程式人生 > >CLR via C#學習筆記-第十二章-泛型方法和其他成員

CLR via C#學習筆記-第十二章-泛型方法和其他成員

12.6 泛型方法

方法和類可以各自定義型別引數

定義泛型類、結構或介面時,型別中定義的任何方法都可以引用型別指定的型別引數。

型別引數可以作為方法引數、返回值或方法內部定義的區域性變數的型別使用。

CLR還允許方法指定他自己的型別引數,這些引數也可以作為引數、返回值或區域性變數的型別使用。

在下例中型別定義了一個型別引數,方法也定義了自己的:

internal sealed class GenericType<T>{
    private T m_value;
    public GenericType(T value){m_value=value;}
    
public TOutput Converter<TOutput>(){ TOutput result=(TOutput)Converter.ChangeType(m_value,typeof(TOutput); return result; } }

Converter方法將欄位引用的物件轉換成任意型別——具體取決於呼叫時傳遞的型別實參是什麼。

 

泛型方法的呼叫

泛型方法的一個很好的例子是Swap方法:

private static void Swap<T>(ref T o1,ref T o2){
    T temp
=o1; o1=o2; o2=temp; }

現在可以這樣呼叫Swap:

private static void CallingSwap(){
    Int32 n1=1;n2=2;
    Swap<Int32>(ref n1,re n2);
    String s1="A",s2="B";
    Swap<String>(ref s1,ref s2);
}

為獲取out和ref引數的方法使用泛型型別很有意思,

因為作為out/ref實參傳遞的變數必需具有與方法引數相同的型別,以免損害型別安全性。

涉及out/ref引數的這個問題在9.3節已作討論。

 

泛型方法和型別推斷

C#編譯器支援在呼叫泛型方法是進行型別託短,增強可讀性、維護性:

private static void CallingSwap(){
    Int32 n1=1;n2=2;
    Swap(ref n1,re n2);
    String s1="A";
    Object s2="B";
    Swap(ref s1,ref s2);//錯誤,不能推斷
}

即使s2是Object,即使他恰好引用一個String,由於s1,s2是不同的資料型別的變數,編譯器拿不準腰圍Swap傳遞什麼型別實參,所以會報錯。

 

方法過載為泛型

型別可以定義多個方法,讓其中一個方法接受具體資料型別,另一個接受泛型引數,如下所示:

private static void Display(String s){
    Console.WriteLine(s);
}
private static void Display(T o){
    Display(o.ToString());
}

下面展示了呼叫Display方法的一些方式:

Display("Jeff");//呼叫Display(String)
Display(123);//呼叫Display<T>(T)
Display<String>("Aidan");//呼叫Display<T>(T)

在第一個調研中,編譯器可以接受第一個String引數的方法也可以接受泛型Display方法。

但C#編譯器的策略是先考慮明確的匹配再考慮泛型匹配。否則會造成無限遞迴。

 

12.7 泛型和其他成員

在C#中,屬性、索引器、時間、操作符方法、構造器和終結器本身不能有型別引數,但它們能在泛型型別中定義。

之所以不允許他們指定自己的泛型型別引數,是因為微軟開發人員認為沒有必要,而且為這些成員新增泛型支援的代價是相當高的。