泛型方法html
在C#2.0中,方法能夠定義特定於其執行範圍的泛型參數,以下所示:編程
即便包含類不適用泛型參數,你也能夠定義方法特定的泛型參數,以下所示:數組
所謂泛型,即經過參數化類型來實如今同一份代碼上操做多種數據類型。泛型編程是一種編程範式,它利用「參數化類型」將類型抽象化,從而實現更爲靈活的複用。ide
在定義泛型類時,能夠對客戶端代碼可以在實例化類時用於類型參數的類型種類施加限制。若是客戶端代碼嘗試使用某個約束所不容許的類型來實例化類,則會產生編譯時錯誤。這些限制稱爲約束。約束是使用 where 上下文關鍵字指定的。函數
下表列出了五種類型的約束:spa
約束 | 說明 |
---|---|
T:struct.net |
類型參數必須是值類型。能夠指定除 Nullable 之外的任何值類型。code |
T:classhtm |
類型參數必須是引用類型,包括任何類、接口、委託或數組類型。blog |
T:new() |
類型參數必須具備無參數的公共構造函數。當與其餘約束一塊兒使用時,new() 約束必須最後指定。 |
T:<基類名> |
類型參數必須是指定的基類或派生自指定的基類。 |
T:<接口名稱> |
類型參數必須是指定的接口或實現指定的接口。能夠指定多個接口約束。約束接口也能夠是泛型的。 |
T:U |
爲 T 提供的類型參數必須是爲 U 提供的參數或派生自爲 U 提供的參數。這稱爲裸類型約束. |
---------------------------------------
一.派生約束
1.常見的
public class MyClass5<T> where T :IComparable { }
2.約束放在類的實際派生以後
public class B { }
public class MyClass6<T> : B where T : IComparable { }
3.能夠繼承一個基類和多個接口,且基類在接口前面
public class B { }
public class MyClass7<T> where T : B, IComparable, ICloneable { }
二.構造函數約束
1.常見的
public class MyClass8<T> where T : new() { }
2.能夠將構造函數約束和派生約束組合起來,前提是構造函數約束出如今約束列表的最後
public class MyClass8<T> where T : IComparable, new() { }
三.值約束
1.常見的
public class MyClass9<T> where T : struct { }
2.與接口約束同時使用,在最前面(不能與基類約束,構造函數約束一塊兒使用)
public class MyClass11<T> where T : struct, IComparable { }
四.引用約束
1.常見的
public class MyClass10<T> where T : class { }
五.多個泛型參數
public class MyClass12<T, U> where T : IComparable where U : class { }
六.繼承和泛型
public class B<T>{ }
1. 在從泛型基類派生時,能夠提供類型實參,而不是基類泛型參數
public class SubClass11 : B<int>
{ }
2.若是子類是泛型,而非具體的類型實參,則能夠使用子類泛型參數做爲泛型基類的指定類型
public class SubClass12<R> : B<R>
{ }
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(){ }
七.泛型方法(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.泛型方法的覆寫
(1)public class MyBaseClass1
{
public virtual void MyMothed<T>(T t) where T : new() { }
}
public class MySubClass1:MyBaseClass1
{
public override void MyMothed<T>(T t) //不能重複任何約束
{ }
}
(2)public class MyBaseClass2
{
public virtual void MyMothed<T>(T t)
{ }
}
public class MySubClass2 : MyBaseClass2
{
public override void MyMothed<T>(T t) //從新定義泛型參數T
{ }
}
八.虛擬方法
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);
}
}
九.編譯器只容許將泛型參數隱式強制轉換到 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;
}
}
十.編譯器容許您將泛型參數顯式強制轉換到其餘任何接口,但不能將其轉換到類
class MyClass1<T>
{
void SomeMethod(T t)
{
ISomeInterface obj1 = (ISomeInterface)t;
//BaseClass obj2 = (BaseClass)t; //不能經過編譯
}
}
十一.使用臨時的 Object 變量,將泛型參數強制轉換到其餘任何類型
class MyClass2<T>
{
void SomeMethod(T t)
{
object temp = t;
BaseClass obj = (BaseClass)temp;
}
}
十二.使用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) { } } }