《C#進階編程》【第五章】泛型,

來源:互聯網
上載者:User

《C#進階編程》【第五章】泛型,


       泛型是進階程式設計語言的一種特性。泛型的引入使得程式開發的效率得到提高,代碼的重用性大大的提升。有了泛型,我們可以建立獨立於被包含類型的類和方法,我們不必給不同的類編寫功能相同的很多方法或者類,只建立一個方法或類就可以了。現在我們看看泛型的優點

       效能上,泛型不需要進行類型轉換(也就是拆箱和裝箱)。
       型別安全,和Object類相比,Object類屬於非型別安全的,而泛型使用泛型型別,可以根據需要用特定的類型替換泛型型別,這樣就保證了型別安全類。在編譯時間,只要與泛型型別T定義的允許使用的類型不同,編譯器就會報錯,這樣我們就可以儘早的發現錯誤。
       二進位代碼重用,在C#中可以一次定義多次使用,然而C++卻要不斷的訪問源碼。
       代碼的擴充,對於參考型別,他們將會共用本地類的所有相同代碼。只有值類型,才會每次執行個體化一個新類。
       我們看完了泛型的優點,我們現在可以來看看泛型具體怎麼使用。我們先看一幅圖,瞭解一下泛型的組成。

1、泛型類
    我們先看看泛型型別的命名方法:<1>一大寫字母T開頭 <2>如果泛型型別沒有特定的要求,或者使用了兩個、兩個以上的泛型型別,就需要給出描述性的名稱。(如:TValue,TKey等等)。
現在我們看看泛型類的聲明文法:

[存取權限修飾符] class 類名<T>{//類體}

       類名的T就是泛型型別,具體類型執行個體化時給出。然而在類體中就可以直接將T當成一個具體的類型來使用。每個處理物件類型的類都可以有泛型實現方式。如果類使用了階層,那麼泛型就可以很好的消除類型轉換的操作。
注意:T兩邊的’<’和’>’不能少。
       在建立泛型類時,我們還需要考慮一些問題。首先我們應該怎麼初始化成員變數呢?然而我們並不知道究竟是參考型別還是值類型,為瞭解決這個問題我們就引入了default關鍵字。文法如下:

T value = default(T)

     這樣我們就圓滿的解決成員變數初始化的問題。default會給值類型賦值為0,參考型別賦值為null。
     如果泛型類需要調用泛型型別的方法,那麼就必須添加約束。那麼什麼是約束呢?約束就是讓泛型型別只能使用我們所約束的類型。我們使用where關鍵字來聲明約束。公有以下6種約束:
<1>where T : struct 結構約束,類型T必須為值類型
<2>where T : class 參考條件約束,類型T必須是參考型別
<3>where T : IFoo 介面約束,類型T必須實現介面IFoo
<4>where T : Foo 類約束,類型T必須派生自基類Foo
<5>where T : new() 類型T必須有一個預設的建構函式
<6>where T1 : T2 裸型約束,類型T1派生自泛型T2。
對於裸型約束,我們來具體說說吧。我們舉個例子:

public class Test<T1, T2> where T1 : T2{//類體}

       我們重點看看執行個體化的時候

var MyTest = new Test<Class1, Class2>();  

       那麼此時,Class1類就必須派生自Class2類,否則編譯器就會報錯。
       使用泛型型別還可以組合多個約束,例如:

public class MyClass<T> where T : IFoo, new(){//類體}

       泛型類,既然作為類那麼它必然可以繼承。泛型類可以實現泛型介面,也可以派生自泛型基類。例:

public class Myclass<T> : IDD<T>{//類體}
或者這樣

public class Base<T>{}public class MySub<T>: Base<T>{}

也可以是這樣:

public class MySub<T>: Base<string>{}

衍生類別可以是泛型類還可以是非泛型類。

public classMysub: Base<int>{}

       泛型類,比較特別的應該就是它的靜態成員了。因為泛型類的靜態成員只能在類的一個執行個體中共用。假設類MySub<T>存在靜態欄位x,那麼如果同時對一個int型和string型使用了Mysub<T>類,所以就存在兩組欄位:Mysub<int>.x和MySub<string>.x
2、泛型介面
        看到泛型介面,我們就要提到,抗變與協變。現在我們就看看什麼抗變與協變。
        假設:TSub是TParent的子類。
        協變:如果一個泛型介面IFoo<T>,IFoo<TSub>可以轉換為IFoo<TParent>的話,我們稱這個過程為協變,IFoo支援對參數T的協變。
        逆變:如果一個泛型介面IFoo<T>,IFoo<TParent>可以轉換為IFoo<TSub>的話,我們稱這個過程為逆變,IFoo支援對參數T的逆變。
        泛型型別的協變用關鍵字out聲明,泛型介面就是協變的,這就意味著其傳回型別只能是T。

public interface IIndex<out T>{T this[int index] {get ;}}

泛型型別的抗變用關鍵字in聲明,泛型介面就是抗變的。這樣泛型型別T就只能作為方法輸入。例如:

public interface IDisplay<in T>{void Show(T test);}

       通常只有具備繼承關係的對象才可以發生隱式類型轉換,如Base b=new sub()。
       協變和逆變可以使得更多的類型之間能夠實現隱式類型轉換、型別安全得到保障。
3、泛型結構
       其實泛型結構和泛型類幾乎是一致的,只是泛型結構沒有繼承的特性。.Net平台提供的一個泛型結構是(可空類型)Nullable<T>。可空類型的引入,主要是為瞭解決資料庫語言中的數字與程式設計語言中的數位區別(資料庫中數字可以為空白,程式設計語言中數字不可為空白)。因為Nullable<T>使用過於的繁瑣,於是我們就引入了一種特殊的文法,使用‘?’運算子。例:

int? x1;Nullable<int> x2;
在上面的例子中,x1與x2這兩種方式定義是等價的。
非空類型可以轉化為可空類型。(總是成功的且可以隱式轉化)
可空類型可以轉化為非空類型。當可空類型的值為null時就會拋出異常。(需要顯示轉化)
如果不進行顯示轉化,我們就可以使用”??”運算子。如下:
int? x1 = GetNullableType();int y1 = x1 ?? 0;

這樣的話,當x1為null時,就會賦給y1一個0。
4、泛型方法
      除了可以定義泛型類,泛型也是可以定義成方法的。文法如下:
[傳回值類型] 方法名稱<T>(參數列表){}
      其餘的用法就和普通方法是一樣的,唯一的區別就是它有一個通用類型T。
      泛型方法和類一樣,也可以加約束,具體約束的方法和泛型類是一樣的。文法如下:
[傳回值類型] 方法名稱<T>(參數列表) where T : [約束方式]{}

以上就是泛型的內容了

聯繫我們

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