目錄
一、泛型的引入
-
泛型---泛:寬泛的---不確定的; 型:類型---不確定的類型
-
無處不在
-
調用普通方法的時候,參數類型在聲明的時候就確定了,調用時按照類型傳遞參數即可;
-
Object類型作為參數,可以傳遞不同的類型進去。
-
泛型方法---做到了性能高---可以一個方法滿足不同類型的需求
二、泛型的聲明設計思想
- 泛型方法:在方法名稱后面多一個尖括號new class Base()
{ },尖括號中有占位符 - 延遲聲明:在執行調用時聲明
- 占位符:T 類型參數——類型變量
- 類型參數當做方法的參數的時候,明確參數類型
三、泛型的原理
1.在高級語言中,定義的泛型T,在計算機執行的執行的時候,必須是一個具體的類型;
2.在底層看到,生成的結果是:List `[T] Dictionary 2 [TKey,TValue]
3.編譯器必須能夠支持泛型
4.CLR運行時環境也必須要支持泛型
5.泛型是框架升級支持的——泛型並非是語法糖
四、泛型的使用
- 泛型方法----可以一個方法滿足不同類型的需求
- 泛型接口----可以一個接口滿足不同類型的需求---尖括號+占位符
- 泛型類------可以一個類型滿足不同類型的需求---尖括號+占位符
- 泛型委托----可以一個委托滿足不同類型的需求
實例代碼
{
//泛型方法
{
GenericInterfac<string> sgenericInterfac = null;
GenericInterfac<DateTime> dtgenericInterfac = null;
}
{
GenericAbstractClass<string> sGenericClass = null;
GenericAbstractClass<DateTime> dtGenericClass = null;
GenericAbstractClass<int> iGenericClass = null;
//sGenericClass dtGenericClass iGenericClass 三者是什么關系?--一沒有關系都沒有
}
{
Genericdelegate<string> sGenericdelegate = null;
Genericdelegate<DateTime> dtGenericdelegate = null;
}
}
五、泛型的約束
為什要有泛型約束?
- Object類型有安全問題,代碼可能會存在隱患,但是編譯器監測不到原因
- 如何避免類型安全問題--泛型--不存在類型安全問題
1.基類約束
- 就是把類型參數當做Cart
- 調用---就可以傳遞Cart或者Cart的子類型
- 泛型約束:要么不讓你進來,如果讓你進來,就一定是沒有問題
- 直接new T()會報錯,可能沒有無參數構造構造函數
示列:
class MyGenericClass<T>
where T : Cart
{
}
2.接口約束
- 把這個T 當做ICart
- 就只能傳遞ICart 這個接口或者是實現過這個接口的類
- 就可以增加功能,可以獲取新的功能
示列:
public class MyGenericClass<T> where T:ICart { }
3.引用類型約束
- 就只能傳遞類型進來
- 直接new T()會報錯,可能沒有無參數構造構造函數
示列:
public class MyGenericClass<T> where T:class
4.值類型約束
- 就只能傳遞值類型進來
示列:
public static void ShowStruct<T>(T t) where T : struct
{
}
5.無參構造函數約束
- 必須有一個無參數構造函數才能當做參數傳入
示列:
public static void ShowNew<T>(T t) where T : new()
{
T model = new T();
}
6.枚舉約束
- 必須是一個枚舉類型才能傳入
示列:
public static void ShowEnum<T>(T t) where T : Enum
{
}
六、協變與逆變
1.泛型的協變/逆變
協變/逆變是一種高級約束,是為了規避:
- 把子類做參數,卻把父類當參數傳入
- 把子類做返回值,卻返回的時候,返回了一個父類
2.協變逆變
- 只針對於泛型接口和泛型委托的
3.協變
-
協變: 就可以讓右邊用子類,能讓左邊用父類
-
協變:Out 類型參數只能做返回值 ,不能做參數
4.逆變
- 逆變:就可以讓右邊用父類;左邊用子類
- 逆變 In : 只能做參數 ,不能做返回值
5.協變逆變的存在
- 就是為了滿足常規場景添加一個避開風險的約束