1. 簡(jiǎn)介:
2.0 版 C# 語(yǔ)言和公共語(yǔ)言運(yùn)行時(shí) (CLR) 中增加了泛型溯街。 泛型將類型參數(shù)的概念引入 .NET Framework,類型參數(shù)使得設(shè)計(jì)如下類和方法成為可能:這些類和方法將一個(gè)或多個(gè)類型的指定推遲到客戶端代碼聲明并實(shí)例化該類或方法的時(shí)候帘瞭。
2. 語(yǔ)法:
class ClassName<Type>
{
public void Add(Type input)
{
}
}
class Program
{
public void test0()
{
ClassName<int> testClass = new ClassName<int>();
testClass.Add(5);
print<int>(5, 6);
print(5, 6); // <>可以省略
}
public void print<T1>(T1 x, T1 y)
{
Console.WriteLine(x.ToString(),y.ToString());
}
}
3. 約束:
1> 約束簡(jiǎn)介
在定義泛型類時(shí)淑掌,可以對(duì)客戶端代碼能夠在實(shí)例化類時(shí)用于類型參數(shù)的類型種類施加限制。 如果客戶端代碼嘗試使用某個(gè)約束所不允許的類型來(lái)實(shí)例化類蝶念,則會(huì)產(chǎn)生編譯時(shí)錯(cuò)誤抛腕。 這些限制稱為約束。 約束是使用 where
上下文關(guān)鍵字指定的媒殉。 下表列出了六種類型的約束:
約束 | 說(shuō)明 |
---|---|
T : struct | 類型參數(shù)必須是值類型担敌。 |
T : class | 類型參數(shù)必須是引用類型;這一點(diǎn)也適用于任何類廷蓉、接口全封、委托或數(shù)組類型。 |
T:new() | 類型參數(shù)必須具有無(wú)參數(shù)的public構(gòu)造函數(shù)桃犬。 當(dāng)與其他約束一起使用時(shí)刹悴,new() 約束必須最后指定。 |
T:<基類名> | 類型參數(shù)必須是指定的基類或派生自指定的基類攒暇。 |
T:<接口名稱> | 類型參數(shù)必須是指定的接口或?qū)崿F(xiàn)指定的接口土匀。 可以指定多個(gè)接口約束。 約束接口也可以是泛型的形用。 |
T:U | 為 T 提供的類型參數(shù)必須是為 U 提供的參數(shù)或派生自為 U 提供的參數(shù)就轧。 |
2> 約束簡(jiǎn)介案例
class TestClass<TestType> where TestType : struct
{
}
static void Main(string[] args)
{
TestClass<int> t1 = new TestClass<int>();
//TestClass<string> t2 = new TestClass<string>(); 錯(cuò)誤,只能傳遞值類型
}
3> 使用泛型約束的原因(優(yōu)勢(shì))
如果要檢查泛型列表中的某個(gè)項(xiàng)以確定它是否有效尾序,或者將它與其他某個(gè)項(xiàng)進(jìn)行比較钓丰,則編譯器必須在一定程度上保證它需要調(diào)用的運(yùn)算符或方法將受到客戶端代碼可能指定的任何類型參數(shù)的支持。 這種保證是通過(guò)對(duì)泛型類定義應(yīng)用一個(gè)或多個(gè)約束獲得的每币。 例如,基類約束告訴編譯器:僅此類型的對(duì)象或從此類型派生的對(duì)象才可用作類型參數(shù)琢歇。 一旦編譯器有了這個(gè)保證兰怠,它就能夠允許在泛型類中調(diào)用該類型的方法梦鉴。
可以對(duì)同一類型參數(shù)應(yīng)用多個(gè)約束,并且約束自身可以是泛型類型揭保,如下所示:
class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new()
{
// ...
}
4> 泛型約束的注意點(diǎn):
通過(guò)約束類型參數(shù)肥橙,可以增加約束類型及其繼承層次結(jié)構(gòu)中的所有類型所支持的允許操作和方法調(diào)用的數(shù)量。 因此秸侣,在設(shè)計(jì)泛型類或方法時(shí)存筏,如果要對(duì)泛型成員執(zhí)行除簡(jiǎn)單賦值之外的任何操作或用 System.Object不支持的任何方法,您將需要對(duì)該類型參數(shù)應(yīng)用約束味榛。在應(yīng)用 where T : class 約束時(shí)椭坚,避免對(duì)類型參數(shù)使用 == 和 != 運(yùn)算符,因?yàn)檫@些運(yùn)算符僅測(cè)試引用同一性而不測(cè)試值相等性搏色。
5> 約束多個(gè)參數(shù)
可以對(duì)多個(gè)參數(shù)應(yīng)用約束善茎,并對(duì)一個(gè)參數(shù)應(yīng)用多個(gè)約束,如下面的示例所示
class Base { }
class Test<T, U>
where U : struct
where T : Base, new()
{ }
6> 未綁定的類型參數(shù)
沒(méi)有約束的類型參數(shù)(如公共類 SampleClass<T>{}中的 T)稱為未綁定的類型參數(shù)频轿。 未綁定的類型參數(shù)具有以下規(guī)則:
- 不能使用 !=和 == 運(yùn)算符垂涯,因?yàn)闊o(wú)法保證具體類型參數(shù)能支持這些運(yùn)算符。
- 可以在它們與 System.Object之間來(lái)回轉(zhuǎn)換航邢,或?qū)⑺鼈冿@式轉(zhuǎn)換為任何接口類型耕赘。
- 可以將它們與 [null] 進(jìn)行比較。 將未綁定的參數(shù)與 null進(jìn)行比較時(shí)膳殷,如果類型參數(shù)為值類型鞠苟,則該比較將始終返回 false。
7> 作為約束的類型參數(shù)
將泛型類型參數(shù)作為約束使用秽之,在具有自己類型參數(shù)的成員函數(shù)必須將該參數(shù)約束為包含類型的類型參數(shù)時(shí)非常有用当娱,如下示例所示:
class List<T>
{
void Add<U>(List<U> items) where U : T {/*...*/}
}
在上面的示例中,T在 Add方法的上下文中是一個(gè)類型約束考榨,而在 List 類的上下文中是一個(gè)未綁定的類型參數(shù)跨细。
類型參數(shù)還可在泛型類定義中用作約束。 請(qǐng)注意河质,必須在尖括號(hào)中聲明此類型參數(shù)與任何其他類型的參數(shù):
SampleClass<T, U, V> where T : V { }
8> 為泛型方法添加約束
void SwapIfGreater<T>(ref T lhs, ref T rhs) where T : System.IComparable<T>
{
T temp;
if (lhs.CompareTo(rhs) > 0)
{
temp = lhs;
lhs = rhs;
rhs = temp;
}
}
泛型方法可以使用許多類型參數(shù)進(jìn)行重載冀惭。 例如,下列方法可以全部位于同一個(gè)類中:
void DoWork() { }
void DoWork<T>() { }
void DoWork<T, U>() { }
4. 泛型接口:
語(yǔ)法:
interface ITest1<K>
{
}
一個(gè)接口可定義多個(gè)類型參數(shù)掀鹅,如下所示:
interface ITest1<K, V>
{
}
適用于類的繼承規(guī)則同樣適用于接口:
interface ITest1<S>
{
}
interface ITest2<K> : ITest1<K>
{
}
泛型接口的約束:
interface ITest1<S> where S : class
{
}
泛型接口的約束繼承
interface ITest1<S> where S : class
{
}
interface ITest2<K> : ITest1<K> where K : class
{
}