天天看點

[C#2] 1-泛型1. 泛型概述2. 泛型類型和泛型方法3. 泛型限制

1. 泛型概述

泛型是一種類型的多态;比如當我們寫一個棧或者隊列的時候,需要指定其資料類型,int一份代碼,string一份代碼,object的一份代碼, 這些代碼除了資料類型不同之外其他大部分都是相同的,根據設計模式的思想,抽象出來變化點封裝它, 共同的部分作為共用的代碼。這裡的變化點就是類型了,共同部分就是算法相同,是以就把類型抽象化, 于是乎泛型問世&[個人了解]。

C#泛型由CLR在運作時支援,這使得泛型可以在CLR支援的各種語言上無縫集合; C#泛型代碼在被編譯[第一次編譯]為IL代碼和中繼資料時[泛型版的IL和中繼資料], 采用特殊的占位符來表示泛型類型,并用專有的IL指令支援泛型操作,真正的泛型執行個體化工作發生在JIT編譯[第二次編譯]時。 當JIT編譯器第一次遇到這種特殊的IL和中繼資料時,會利用實際的類型進行替換[泛型類型的執行個體化]。 CLR為所有類型參數是引用類型的泛型類型産生同一份代碼,而對值類型來說,不同的值類型産生不同的代碼, 相同的則共用同一份代碼。

C#泛型類型攜帶有豐富的中繼資料,是以C#的泛型類型可以應用于強大的反射技術;采用[基類, 接口, 構造器, 值類型/引用類型]的限制方式來實作對類型參數的"顯式限制", 提高了類型的安全性。DEMO:

public class MyType<T> where T : struct
{
     private T[] _items;
     public void Add(T itme)
     {
     }
}      

編譯後IL如下:

//泛型類<'1代表元數或者參數數量>
.class public auto ansi beforefieldinit MyType`1<valuetype .ctor 
//注意這裡加上了泛型限制<[mscorlib]System.ValueType) T>
//表明類型參數是值類型的
([mscorlib]System.ValueType) T>
    extends [mscorlib]System.Object
{
} // end of class MyType`1
//這是那個私有字段
.field private !T[] _items
 
//Add方法,類型參數<T>之前有一個感歎号<!>,這是CIL開始支援泛型
//後引入的新特性,它指出為類指定的第一個類型參數的存在,表明這是
//一個類型參數
.method public hidebysig instance void  Add(!T itme) cil managed
{
    // 代碼大小       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
} // end of method MyType`1::Add      

除了這些差別外,泛型類和非泛型類的CIL代碼并無太大差別。

2. 泛型類型和泛型方法

可以用于泛型的類型有類、接口,結構、委托。

C#支援泛型方法,但不支援除方法外的其他成員[屬性、事件、索引器、構造器、析構器。但這些成員本身可以包含在泛型類型中,并使用泛型類型的類型參數]; 泛型方法可以包含在泛型類型中,也可以包含在非泛型類型中[即普通的類型]。泛型方法:

public class GenericsMehod
{
    //非泛型類中的泛型方法,參數限制為引用類型
    //<傳入值類型參數将引起編譯錯誤>
    public int FindItem<T>(T[] items, T item)where T:class
    {
        for (int i = 0; i < items.Length; i++)
        {
            if (items[i].Equals(item))
            {
                return i;
            }
        }
        return -1;
    }
}      

調用就不寫了,泛型方法支援重載,但是之差別類型參數限制的重載是非法的; 也是支援重寫的,重寫時的類型參數的限制被預設繼承,任何的限制的指定都是不必要的,也是不可以指定限制的。

3. 泛型限制

為什麼要有限制呢?假如我寫了一個泛型類,這個泛型參數調用到CompareTo方法, 但是并不是所有的類型參數都有這個方法,假如傳入的類型沒這個方法,就會引起錯誤了, 是以保證你的代碼的健壯的話,加上限制還是很有必要的[就是說傳入的類型必須有這個方法才可以編譯通過, 把錯誤暴露在編譯階段]。泛型限制支援四種形式的限制【接口限制,基類限制,構造器限制,值類型/引用類型限制】; 限制并不是必須的,如果沒有指定限制,那麼類型參數将隻能通路System.Object類型中的公有方法。文法為where語句

上面的類型參數需要一個CompareTo方法就可以用一個接口限制加以實作:

public class MyGenerics<T>; where T : IComparable{}      

基類限制:表是類型參數必須是繼承子指定的類型<where T : 基類>;

構造器限制:隻支援無參的構造器限制,就是必須保障參數類型可以調用它的無參構造器<where T : new()>:

值類型/引用類型限制:隻有兩種情況了<where T:struct>或者<where T:class>,指定參數類型必須是值類型或者引用類型;

作者:

Blackheart

出處:

http://linianhui.cnblogs.com

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

繼續閱讀