C# 語法之泛型
一.什麼是泛型
泛型其實就是一個不確定的型別,可以在類或方法上使用。泛型在宣告期間沒有明確定義型別,編譯後生成一個佔位符,只有在呼叫後傳入型別,才會將該確切的型別將佔位符替換掉。
二.泛型的定義
//用在類中 public class ClassName<CName> { //用在方法中 public void Mothed<MName>() { } //泛型類中具體使用CName //返回值為CName並且接受一個型別為CName型別的物件 public CName GetC(CName c) { } }
這裡的CName和MName是可變的型別(名字也是可變),可以讓呼叫者來決定要使用的型別。
三.使用
下面舉個例子。
public class Animal { //會跑的方法 public virtual void CanRun() { Console.WriteLine("Animal Run Can"); } } public class Dog : Animal { //重寫父類方法 public override void CanRun() { Console.WriteLine("Dog Can Run"); } } public class Cat : Animal { //重寫父類方法 public override void CanRun() { Console.WriteLine("Cat Can Run"); } }
再定義一個animalHouse來存放所有的動物。
public class AnimalHouse { private List<Animal> animals = new List<Animal>(); //新增方法 public void AddAnimal(Animal a) { animals.Add(a); } }
AnimalHouse可以存放所有的動物,但如果取出來,使用就有些不方便。現在放進去Dog和Cat,你可以將所有動物都帶出來跑步。假如Dog有個方法是Canswin()游泳的方法,那這裡是調用不了,animal沒有這個方法。
如果使用泛型的話,就可以由呼叫者決定使用哪種型別。在AnimalHouse將所有animal改為泛型。
public class AnimalHouse<T> { private List<T> animals = new List<T>(); //新增方法 public void AddAnimal(T a) { animals.Add(a); } }
AnimalHouse想存放什麼型別,由呼叫者決定。
//宣告存放所有Dog型別的集合 AnimalHouse<Dog> dog = new AnimalHouse<Dog>(); //宣告存放所有Cat型別的集合 AnimalHouse<Cat> cat = new AnimalHouse<Cat>();
傳入哪個型別,原本的T就會編譯成具體的型別。animalHouse可以讓我們來自己構造存放哪種動物的集合。該集合就可以具體使用集合中動物特有的方法。
這裡還有個問題,原本AnimalHouse只能存放animal,現在是泛型T,那就算是非animal的類也可以存進去,不符合最初的設計。所以為了型別安全,需要對傳入的型別進行約束。
四.泛型約束
泛型約束就是對泛型(傳入的型別)進行約束,約束就是指定該型別必須滿足某些特定的特徵,例如可以被例項化,實現Animal類等。舉個例子。
class Base { } class Test<T, U> where U : struct where T : Base, new() { }
使用的話,只需要在泛型後面加上where來使用。
where T : struct。型別必須為值型別。
where T : class。型別必須為引用型別。
where T : new()。型別引數必須具有公共無引數建構函式。與其他約束一起使用時,new()
約束必須最後指定。
where T : <基類名>。型別引數必須是指定的基類或派生自指定的基類。
where T : <介面名稱>。型別引數必須是指定的介面或實現指定的介面。可指定多個介面約束。約束介面也可以是泛型。
然後,我們來為AnimalHouse新增泛型約束為:必須包含公共無參建構函式和基數必須為Animal。
//Animal約束T必須是Animal的子類或者本身,new()約束放在最後 public class AnimalHouse<T> where T : Animal, new() { private List<T> animals = new List<T>(); //新增方法 public void AddAnimal(T a) { //呼叫CanRun方法 //如果不加Animal泛型約束是無法呼叫.CanRun方法的,因為型別是不確定的 a.CanRun(); animals.Add(a); } }
現在AnimalHouse類限制要傳入的引數是,必須繼承Animal,且有公共無參建構函式的。