標籤:class blog code http com get
委託讓方法參數化,而泛型實現了型別參數化。
一、泛型型別的聲明規則:
1、在類名稱後跟一對角括弧,括弧中為若干個型別參數,多個型別參數之間使用逗號進行分隔,型別參數實際上是個類型預留位置。如、public class MyClass<T>{},T只是個習慣,實際上用其他字母也完全可以。
2、在類聲明的主體中使用型別參數來表示應該被替代的類型,一般是方法的參數類型,傳回型別,或者作為欄位、屬性的類型。
樣本1:
public class MyClass<T1, T2> { public T1 field1; //在類內部泛型型別還能用 public T2 field2; public T1 GetField1() //作為傳回值 { return field1; } public T2 GetField2() { return field2; } public void SetField1(T1 data) //作為方法參數類型 { field1 = data; } public void SetField2(T2 data) { field2 = data; } }
泛型能夠根據傳入的不同類型,實施不同的處理。重用了代碼邏輯,將類型抽象了出來。
泛型的類型約束,通過約束能夠對類型實參添加一定的限制條件,約束是通過使用內容關鍵字的where應用的,只需要在泛型型別聲明的角括弧後面使用where關鍵字,後面緊跟型別參數和約束類型,中間使用冒號分隔即可。
類型約束一共有6種,如下所示:
約束類型 |
說明 |
where T : class |
類型實參必須是參考型別,包括任何類、介面、委託或數群組類型 |
where T : struct |
類型實參必須是實值型別,可以是任何實值型別,但不包括Nullable |
where T : <基類名> |
類型必須是指定的類或者它的衍生類別 |
where T : <介面名> |
類型必須是實現了指定的介面或者實現了該介面的類型,可以指定多個介面約束,約束介面也可以是泛型的 |
where T : new() |
類型實參必須有一個無參數的公用建構函式 |
where T : U |
類型實參T必須是類型實參U,或者是U的衍生類別,這稱作裸類型約束 |
同時還必須要注意,當需要添加多個類型約束時,約束之間用逗號分隔。同時對於某一個型別參數的多種約束類型,where字句與where字句之間沒有次序要求,但是對於where字句內部是有次序要求的。具體次序如下:
- 如果有class,struct,基類這三種類型約束,則必須放在第一位。
- 之後是介面約束,數量不限
- 如果有new(),則必須放在最後。
如:
public class TestType<T,V> where T : Person where V : new(){} //where與where字句沒有次序要求 public class TestType<T> where T : class,IList,new(){} //where字句內部有類型要求
class Program { static void Main(string[] args) { Person P = new Person(); P.Id = 1; P.Name = "張三"; TestType<Person> tt = new TestType<Person>(); string str = tt.getType(P); Console.WriteLine(str); //輸出張三 Console.ReadKey(); } } public class TestType<T> where T : Person //指定實參類型必須是Person類或Person類的衍生類別 { public string getType(T data) { return data.Name; } } public class Person { public int Id; public string Name; }
泛型方法與泛型類很相似。一下給出兩個泛型方法的例子。
class Program { static void Main(string[] args) { Person p = new Person(); p.Id = 1; SetName<Person>(p); Console.WriteLine(p.Name); //輸出張飛 Console.ReadKey(); } public static Person SetName<T>(T per) where T : Person { per.Name = "張飛"; return per; } } class Person { public int Id { get; set; } public string Name { get; set; } } class Program { static void Main(string[] args) { string str = "你好!"; Console.WriteLine(GetMessage<string>(str)); //輸出System.String Console.ReadKey(); } public static Type GetMessage<T>(T Message) { return Message.GetType(); } }
泛型的擴充方法,與擴充方法一樣,只是有點怪異罷了。給個樣本:
class Program { static void Main(string[] args) { Person<string> per = new Person<string>(); per.Person<string>("關羽"); //這樣子來調用擴充方法,自己都看不懂牛得一B Console.WriteLine(per.Name); Console.ReadKey(); } } public static class Set { public static void Person<T>(this Person<T> p, T Name) { p.Name = Name; } } public class Person<T> { public int Id { get; set; } public T Name { get; set; } }
泛型委派和非泛型委派也很相似,只是泛型委派進行了一層抽象,將中間涉及的操作類型以及傳回值類型抽象為了型別參數,以便更大限度地複用該委託。
public delegate T PrintDelegate<T>(T data); class Program { static void Main(string[] args) { PrintDelegate<string> StrDelegate = PString; //委託的定義中,3個大T都是string string outStr = StrDelegate("我是一個兵"); //調用委託 Console.WriteLine(outStr); //輸出委託傳回值 我是一個兵我是一個兵 PrintDelegate<int> IntDelegate = PInt; //型別參數傳入int,則參數類型,傳回值類型,都是int int outInt = PInt(3); //由於參數類型設為了int,因此只能綁定參數跟傳回值為int的方法 Console.WriteLine(outInt); //輸出 6 Console.ReadKey(); } public static string PString(string str) { return str + str; } public static int PInt(int i) { return i + i; } }
泛型的協變與逆變