C# 泛型約束 xxx Where T:約束(二)

 

泛型是什麼?

經過上篇的實例  C# 泛型約束 xxx<T> Where T:約束(一),咱們對泛型有必定的認識。html

所謂泛型,即經過參數化類型來實如今同一份代碼上操做多種數據類型,泛型編程是一種編程範式,它利用「參數化類型」將類型抽象化,從而實現更爲靈活的複用。編程

在定義泛型類時,能夠對代碼可以在實例化類時用於類型參數的類型種類施加限制。若是代碼嘗試使用某個約束所不容許的類型來實例化類,則會產生編譯時錯誤。這些限制稱爲約束。約束是使用 where 上下文關鍵字指定的。數組

五種類型的約束

下表列出了五種類型的約束:ide

約束 說明
T:struct 類型參數必須是值類型。能夠指定除 Nullable 之外的任何值類型。
T:class 類型參數必須是引用類型,包括任何類、接口、委託或數組類型。
T:new () 類型參數必須具備無參數的公共構造函數。當與其餘約束一塊兒使用時,new() 約束必須最後指定。
T:<基類名> 類型參數必須是指定的基類或派生自指定的基類。
T:<接口名稱> 類型參數必須是指定的接口或實現指定的接口。能夠指定多個接口約束。約束接口也能夠是泛型的。
T:U 爲 T 提供的類型參數必須是爲 U 提供的參數或派生自爲 U 提供的參數。這稱爲裸類型約束.

image

1. 派生約束

1.常見的

public class MyClass5<T> where T :IComparable { }函數

2.約束放在類的實際派生以後

public class B { }spa

public class MyClass6<T> : B where T : IComparable { }code

3.能夠繼承一個基類和多個接口,且基類在接口前面

public class B { }htm

public class MyClass7<T> where T : B, IComparable, ICloneable { }blog

2. 構造函數約束

1.常見的

public class MyClass8<T> where T :  new() { }繼承

2.約束組合

能夠將構造函數約束和派生約束組合起來,前提是構造函數約束出如今約束列表的最後

public class MyClass8<T> where T : IComparable, new() { }

3. 值約束

1.常見的

public class MyClass9<T> where T : struct { }

2. 接口約束同時使用

與接口約束同時使用,在最前面(不能與基類約束,構造函數約束一塊兒使用)

public class MyClass11<T> where T : struct, IComparable { }

4. 引用約束

1.常見的

public class MyClass10<T> where T : class { }

5. 多個泛型參數

public class MyClass12<T, U> where T : IComparable  where U : class { }

6. 繼承和泛型

public class B<T>{ }

1.類型實參

1. 在從泛型基類派生時,能夠提供類型實參,而不是基類泛型參數

    public class SubClass11 : B<int>{ }

2.子類泛型做爲基類泛型的指定類型

2.若是子類是泛型,而非具體的類型實參,則能夠使用子類泛型參數做爲泛型基類的指定類型

    public class SubClass12<R> : B<R>{ }

3.子類重複基類的約束

3.在子類重複基類的約束(在使用子類泛型參數時,必須在子類級別重複在基類級別規定的任何約束)
    public class B<T> where T : ISomeInterface { }
    public class SubClass2<T> : B<T> where T : ISomeInterface { }

4.構造函數約束

public class B<T> where T : new()
{
    public T SomeMethod()
    {
        return new T();
    }
}
public class SubClass3<T> : B<T> where T : new() { }

 

7. 泛型方法

C#2.0泛型機制支持在"方法聲名上包含類型參數",這就是泛型方法)

1.泛型類型/非泛型類型

泛型方法既能夠包含在泛型類型中,又能夠包含在非泛型類型中

public class MyClass5
{
    public void MyMethod<T>(T t){ }
}

2.泛型方法的聲明與調用

public class MyClass5
{
    public void MyMethod<T>(T t)
    {
    }
}

public class App5
{
    public void CallMethod()
    {
        MyClass5 myclass5 = new MyClass5();
        myclass5.MyMethod<int>(3);
    }
}

3.泛型方法的重載

//第一組重載
void MyMethod1<T>(T t, int i) { }

void MyMethod1<U>(U u, int i) { }

//第二組重載
void MyMethod2<T>(int i) { }
void MyMethod2(int i) { }

//第三組重載,假設有兩個泛型參數
void MyMethod3<T>(T t) where T : A { }
void MyMethod3<T>(T t) where T : B { }

//第四組重載

public class MyClass8<T, U>
{
    public T MyMothed(T a, U b)
    {
        return a;
    }
    public T MyMothed(U a, T b)
    {
        return b;
    }
    public int MyMothed(int a, int b)
    {
        return a + b;
    }
}

4.泛型方法的覆寫

public class MyBaseClass1
{
    public virtual void MyMothed<T>(T t) where T : new() { }
}
public class MySubClass1 : MyBaseClass1
{
    //不能重複任何約束
    public override void MyMothed<T>(T t) { }
}

public class MyBaseClass2
{
    public virtual void MyMothed<T>(T t){ }
}
public class MySubClass2 : MyBaseClass2
{
    //從新定義泛型參數T
    public override void MyMothed<T>(T t){ }
}

8. 虛擬方法

public class BaseClass4<T>
{
    public virtual T SomeMethod()
    {
        return default(T);
    }
}
public class SubClass4 : BaseClass4<int> //使用實參繼承的時候方法要使用實參的類型
{
    public override int SomeMethod()
    {
        return 0;
    }
}

public class SubClass5<T> : BaseClass4<T> //使用泛型繼承時,方法也是泛型
{
    public override T SomeMethod()
    {
        return default(T);
    }
}

9. 泛型參數強制轉換到Object或約束指定的類型

編譯器只容許將泛型參數隱式強制轉換到 Object 或約束指定的類型

class MyClass<T> where T : BaseClass, ISomeInterface
{
    void SomeMethod(T t)
    {
        ISomeInterface obj1 = t;
        BaseClass obj2 = t;
        object obj3 = t;
    }
}

//變通方法:使用臨時的 Object 變量,將泛型參數強制轉換到其餘任何類型

class MyClass2<T>
{
    void SomeMethod(T t)
    {
        object temp = t;
        BaseClass obj = (BaseClass)temp;
    }
}

10. 泛型參數強制轉換到其餘任何接口

編譯器容許您將泛型參數顯式強制轉換到其餘任何接口,但不能將其轉換到類

class MyClass1<T>
{
    void SomeMethod(T t)
    {
        ISomeInterface obj1 = (ISomeInterface)t;
        //BaseClass obj2 = (BaseClass)t;           //不能經過編譯
    }
}

11. 泛型參數強制轉換到其餘任何類型

使用臨時的 Object 變量,將泛型參數強制轉換到其餘任何類型

class MyClass2<T>
{
    void SomeMethod(T t)
    {
        object temp = t;
        BaseClass obj = (BaseClass)temp;
    }
}

12. 使用is和as運算符

public class MyClass3<T>
{
    public void SomeMethod(T t)
    {
        if (t is int) { }
        if (t is LinkedList<int>) { }
        string str = t as string;
        if (str != null) { }
        LinkedList<int> list = t as LinkedList<int>;
        if (list != null) { }
    }
}

參考資料

MSDN:http://msdn.microsoft.com/zh-cn/library/d5x73970.aspx

部份內容參考:http://www.cnblogs.com/andrew-blog/archive/2012/03/21/ListT_Where.html

相關文章
相關標籤/搜索