layui複選框全選,單選取消全選
1. 泛型的意義
型別安全(更好的編譯時檢查),效能增強(避免裝箱和拆箱),程式碼複用(減少了功能相似的程式碼)
2. 種類:
- 泛型型別(包括類,結構,介面,委託,陣列)
- 泛型方法。
列舉、屬性、建構函式、欄位 這些沒有對應的泛型
3. 約束 :
- where T: class (必須是引用型別)
- where T:struct (必須是值型別,nullable 型別的值型別除外)
- where T: 基類名 (限制類型引數必須是繼承自指定的基類,或是基類本身)
- new() (必須有無參建構函式,只能用於引用型別,並且必須放在約束的最後如
class Sample<T> where T : class, IDisposable, new()
- where T:介面名 (限制類型引數必須是實現指定介面)
- where T:U (為 T 提供的型別引數必須是為 U 提供的引數或派生自為 U 提供的引數。這稱為裸型別約束.)
- 組合約束
上面的幾種約束可以形成組合約束。若一個型別引數有多個約束,約束之間用
,
分開; 如果包含多個型別引數 ,多個型別引數用where
分開。如public class KeyValue<TKey,TValue> where TKey : new() where TValue: Base,new()
4. 相關術語:
- 形參(一般用 paramter 描述)
- 實參(一般用 argument 描述)
- 型別引數:是一種形參,如
List<T>
中的T
- 型別實參 ,如
List<int>
中的int
- 泛型的 開放型別
指的是帶有 型別引數(且未分配型別實參) 的型別,如
Type myType= typeof(List<T>) ;
中的變數 myType; - 泛型的 封閉型別; 已經分配具體 型別實參 的型別,如
Type myType2= typeof(List<int>) ;
中的變數 myType2;
5. 泛型方法
- 帶有型別引數的方法不一定都是泛型方法
public class Animal<T> { public void Move1(T speed) { } public void Move2<S>(S speedT) { } }
Move2
是泛型方法 , Move1
則不是. 判斷一個方法是否是泛型方法,可以通過反射獲取到 MethodInfo
物件,然後呼叫 物件的 IsGenericMethod
方法.
方法過載: 呼叫方法時,如果有多個方法簽名相匹配,則優先呼叫型別引數較少的方法
方法呼叫時 型別引數的省略,如果是下面的 2 種情況則可以省略型別引數
- 使用型別明確的值,傳給被呼叫的方法時 如
Move<int>(100); // 可以簡寫成 Move(100);
- 使用泛型方法呼叫另一個具有相同方法簽名的泛型方法時
public void Move<T>(T speed){}
public void MoveWrapper<T>(T s)
{
Move<T>(s);// 可以簡寫成 Move(s);
}
4. 協變和逆變:
- 協變和逆變指的是泛型的型別實參之間的型別轉換 。且協變和逆變都是型別安全的.
C# 只對 介面 和 委託 提供可變性支援(包括協變和逆變),另外支援
陣列
的協變(但是僅僅是編譯時不報錯,允許時訪問到內部的具體元素還是會出現執行時異常,這樣設計的原因據說是為了相容 Java)。 型別引數前加in
或out
,這種寫法是 C# 4.0 才引人的, 這也表明之前的 C#版本不支援協變和逆變
- 協變(Covariance 允許使用比原始指定的型別派生程度更大的型別)
通用的表示是
Ixxx<父類或父介面> iBase = new xxx<子類或子介面>();
,其中
Ixxx
介面中必然有型別引數
前面帶有out
關鍵字修飾 如:IEnumerable<Animal> animals= new List<Cat>();
當泛型的型別引數只描述返回型別引數(輸出)的操作時,協變是型別安全的; 若型別引數前加 out ,表明該型別只能作為函式的返回型別使用,不能作為輸入 - 逆變(Contravariance 允許使用比原始指定的型別派生程度更小的型別)
通用的表示是
Ixxx<子類或子介面> iBase = new xxx<父類或父介面>();
其中Ixxx
介面中必然有型別引數
前面帶有in
關鍵字修飾。 如:
Action<Base> b = (target) => { Console.WriteLine(target.GetType().Name); };
Action<Derived> d = b;
d(new Derived());
當型別引數只描述接受型別引數(輸入)的操作時,逆變就是安全的 。 若型別引數前加 in ,表明該型別只能作為函式的輸入型別使用,不能作為輸出型別。
- 不變體(Invariance 只能使用原始指定的型別;泛型型別引數既不是協變型別,也不是逆變型別) 如:
List<Cat> cats= new List<Cat>();
5. 進階內容
- 泛型型別內的靜態欄位:
不同的封閉型別具有不同的靜態欄位
- JIT 編譯器如何處理泛型
- JIT 為每個以值型別作為型別實參的 封閉型別 都建立不同的程式碼
- 所有使用引用型別作為型別實參的 封閉型別 都共享相同的本機程式碼 這是因為所有引用型別的變數實際上只是指向堆上物件的指標.而所有的指標都可以使用相同的方式操作.