泛型
一、什么是泛型?
通過泛型可以定義類型安全類,而不會損害類型安全、性能或工作效率
二、實例化泛型
1、可以使用任何類型來聲明和實例化
2、申明和實例話都必須用一個特定的類型來代替一般類型T
3、例子:
//原來寫法
Public class Stack
{
object[] m_Items;
public void Push(object item)
{...}
public object Pop()
{...}
}
Stack stack = new Stack();
stack.Push(1);
int number = (int)stack.Pop();
//有了泛型后
Public class Stack <T>
{
T[] m_Items;
public void Push(T item)
{...}
public T Pop()
{...}
}
Stack <int> stack = new Stack <int> ();
stack.Push(1);
int number = (int)stack.Pop();
三:泛型的好處
1、一次性的開發、測試和部署代碼,通過任何類型來重用它
2、編譯器支持和類型安全
3、不會強行對值類型進行裝箱和取消裝箱,或者對引用類型進行向下強制類型轉換,所以性能得到顯著提高。
注:值類型大概可以提高200%,引用類型大概為100%
四:多個泛型
1、單個類型可以定義多個泛型
五:泛型別名
1、在文件頭部使用using 為特定類型取別名,別名作用范圍是整個文件
2、例子
using List = LinkedList <int,string> ;
class ListClient
{
static void Main(string[] args)
{
List list = new List();
list.AddHead(123, "AAA ");
}
}
五:泛型約束
(1)、派生約束
如:
public class LinkedList <K,T> where K:IComparable
{
T Find(K key)
{
if (str.Key.CompareTo(key) == 0)//只有實現這個接口才可比較
}
}
注意:
1、所有的派生約束必須放在類的實際派生列表之后
如:public class LinkedList <K,T> :IEnumerable <T> where K:IComparable <K>
{...}
2、一個泛型參數上可以約束多個接口(用逗號分隔)
public class LinkedList <K,T> where K:IComparable <K> ,IConvertible
3、在一個約束中最多只能使用一個基類
4、約束的基類不能是密封類或靜態類
5、不能將System.Delegate或System.Array約束為基類
6、可以同時約束一個基類以及一個或多個接口,但是該基類必須首先出現在派生約束列表中。
7、C#允許你將另一個泛型參數指定為約束
public class MyClass <T,U> where T:U
{...}
8、可以自己定義基類或接口進行泛型約束
9、自定義的接口或基類必須與泛型具有一致的可見性
(2)、構造函數約束
如:
class Node <K,T> where T:new()
{
}
注意:
1、可以將構造函數的約束和派生約束結合起來,前提是構造函數的約束出現在約束列表中的最后
(3)、引用/值類型約束
1、可以使用struct約束將泛型參數約束為值類型(如int、bool、enum),或任何自定義結構
2、同樣可以使用class約束將泛型參數約束為引用類型
3、不能將引用/值類型約束與基類約束一起使用,因為基類約束涉及到類
4、不能使用結構和默認構造函數約束,因為默認構造函數約束也涉及到類
5、雖然您可以使用類和默認構造函數約束,但是這樣做沒有任何價值
6、可以將引用/值類型約束與接口約束組合起來,前提是引用/值類型約束出現在約束列表的開頭
六:泛型和強制類型轉換
1、C#編譯器只允許將泛型參數隱式轉換到Object或約束指定的類型
如:
interface IS{...}
class BaseClass{...}
class MyClass <T> where T:BaseClass,IS
{
void SomeMethod(T t)
{
IS obj1 = t;
BaseClass obj2 = t;
object obj3 = t;
}
}
2、編譯器允許你將泛型參數顯示強制轉換到其他任何借口,但不能將其轉換到類
interface IS{...}
class SomeClass{...}
class MyClass <T> //沒有約束
{
void SomeMethod(T t)
{
IS obj1 = (IS)t; //可以
SomeClass obj2 = (SomeClass)t //不可以
}
}
3、可以使用臨時的Object變量,將泛型參數強制轉換到其他任何類型
class SomeClass{...}
class MyClass <T>
{
void SomeMethod(T t)
{
object temp = t;
SomeClass obj = (SomeClass)temp;//可以
}
}
注意:這里只是告訴你這樣寫是可以的,但是要不要這樣寫?不要這樣寫,因為如果t確實沒有繼承SomeClass編譯沒錯但是運行就會出錯
4、解決上面強制轉換問題,可以使用is和as運算符進行判斷
public class MyClass <T>
{
public void SomeMethod <T t>
{
if (t is int ){...}
if (t is LinkedList <int,string> ){...}
//如果泛型參數的類型是所查詢的類型,則is運算符返回true
string str = t as string;
//如果這寫類型兼容,則as將執行強制類型轉換,否則將返回null
if (str != null){...}
LinkedList <int,string> list = t as LinkedList <int,string> ;
if (list != null){...}
}
}
七:繼承和泛型
1、在從泛型基類派生,可以提供類型實參,而不是基類泛型參數
public class BaseClass <T> {...}
public class SubClass:BaseClass <int>
2、如果子類是泛型,而非具體的類型實參,則可以使用子類泛型參數作為泛型基類的指定類型
public class BaseClass <TT> {...}
public class SubClass <T> :BaseClass <T> {...}
3、在使用子類泛型參數時,必須在子類級別重復在基類級別規定的任何約束
4、基類可以定義其簽名使用泛型參數的虛禮方法,在重寫它們時,子類必須在方法簽名中提供相應的類型。
如:
public class BaseClass <T>
{
public virtual T SomeMethod()
{...}
}
public class SubClass:BaseClass <int>
{
public override int SomeMethod()
{...}
}
5、如果該子類是泛型,則它還可以在重寫時使用它自己的泛型參數
public class SubClass <T> :BaseClass <T>
{
public override T SomeMethod()
{...}
}
6、你可以定義泛型接口、泛型抽象類,甚至泛型抽象方法。
7、不能對泛型參數使用+或+=之類的運算符
public class Calculator <T>
{
public T Add (T arg1,T arg2)
{
return arg1 + arg2;//錯誤
}
}
但是我們可以通過泛型抽象類、接口來實現在個功能,因為實現泛型抽象類、接口我們就已經明確傳一個參數了,就可以執行諸如+這樣的操作。
八:泛型方法
1、方法可以定義特定於其執行范圍的泛型參數
public class MyClass <T>
{
public void MyMethod <X> (X x)
{...}
}
2、即使各包含類根本不使用泛型,你也可以定義方法特定的泛型參數
public class MyClass
{
public void MyMethod <T> (T t)
{...}
}
注意:該功能只使用於方法,屬性,索引器只能使用在類的作用范圍中定義的泛型參數。
3、調用泛型方法
MyClass obj = new MyClass();
obj.MyMethod <int> (3);
也可以這樣:
MyClass obj = new MyClass();
obj.MyMethod(3); //該功能稱為泛型推理
4、泛型方法也可以有自己的泛型參數約束
pubic class MyClass
{
public void SomeMethod <T> (T t) where T:IComparable <T>
{...}
}
5、子類方法實現不能重復在父級別出現的約束
public class BaseClass
{
public virtual void SomeMethod <T> (T t)where T:new()
{...}
}
pubic class SubClass:BaseClass
{
public override void SomeMethod <T> (T t)//不能再有約束
{...}
}
6、靜態方法
靜態方法可以定義特定的泛型參數和約束
public class MyClass <T>
{
public static T SomeMethod <X> (T t,X x)
{...}
}
int number = MyClass <int> .SomeMethod <string> (3, "AAA ");
或者:int mumber = MyClass <int> .SomeMethod(3, "AAA ");
九:泛型委托
1、在某個類中定義的委托可以利用該類的泛型參數
2、委托也可以定義自己的泛型參數
1.泛型和泛型強制轉換 using System; using System.Collections.Generic; using System.Text; namespace VS2005Demo2 6{ 7 8 C# 編譯器只允許將泛型參數隱式強制轉換到 Object 或約束指定的類型#region C# 編譯器只允許將泛型參數隱式強制轉換到 Object 或約束指定的類型 9 public interface ISomeInterface 10 { } 11 class BaseClass 12 { } 13 class MyClass<T> where T : BaseClass, ISomeInterface 14 { 15 void SomeMethod(T t) 16 { 17 ISomeInterface obj1 = t; 18 BaseClass obj2 = t; 19 object obj3 = t; 20 } 21 } 22 #endregion 23 24 編譯器允許您將泛型參數顯式強制轉換到其他任何接口,但不能將其轉換到類#region 編譯器允許您將泛型參數顯式強制轉換到其他任何接口,但不能將其轉換到類 25 class SomeClass 26 { } 27 //class MyClass1<T> 28 //{ 29 // void SomeMethod(T t) 30 // { 31 // ISomeInterface obj1 = (ISomeInterface)t; //Compiles 32 // SomeClass obj2 = (SomeClass)t; //Does not compile 33 // } 34 //} 35 #endregion 36 37 38 使用臨時的 Object 變量,將泛型參數強制轉換到其他任何類型#region 使用臨時的 Object 變量,將泛型參數強制轉換到其他任何類型 39 class MyClass2<T> 40 { 41 void SomeMethod(T t) 42 { 43 object temp = t; 44 SomeClass obj = (SomeClass)temp; 45 } 46 } 47 #endregion 48 49 使用is和as運算符#region 使用is和as運算符 50 public class MyClass3<T> 51 { 52 public void SomeMethod(T t) 53 { 54 if (t is int) { } 55 if (t is LinkedList<int, string>) { } 56 string str = t as string; 57 if (str != null) { } 58 LinkedList<int, string> list = t as LinkedList<int, string>; 59 if (list != null) { } 60 } 61 } 62 #endregion 63 64} 65 2.繼承和泛型 1using System; 2using System.Collections.Generic; 3using System.Text; 4 5namespace VS2005Demo2 6{ 7 繼承和泛型#region 繼承和泛型 8 public class BaseClass<T> 9 { } 10 public class SubClass : BaseClass<int> 11 { } 12 13 14 public class SubClass1<R> : BaseClass<R> 15 { } 16 #endregion 17 18 繼承約束#region 繼承約束 19 public class BaseClass1<T> where T : ISomeInterface 20 { } 21 public class SubClass2<T> : BaseClass1<T> where T : ISomeInterface 22 { } 23 24 //構造函數約束 25 public class BaseClass3<T> where T : new() 26 { 27 public T SomeMethod() 28 { 29 return new T(); 30 } 31 } 32 public class SubClass3<T> : BaseClass3<T> where T : new() 33 { } 34 35 #endregion 36 37 虛擬方法#region 虛擬方法 38 public class BaseClass4<T> 39 { 40 public virtual T SomeMethod() 41 { 42 return default(T); 43 } 44 } 45 public class SubClass4 : BaseClass4<int> 46 { 47 public override int SomeMethod() 48 { 49 return 0; 50 } 51 } 52 53 public class SubClass5<T> : BaseClass4<T> 54 { 55 public override T SomeMethod() 56 { 57 return default(T); 58 } 59 } 60 61 #endregion 62 63 接口、抽象類繼承#region 接口、抽象類繼承 64 public interface ISomeInterface6<T> 65 { 66 T SomeMethod(T t); 67 } 68 public abstract class BaseClass6<T> 69 { 70 public abstract T SomeMethod(T t); 71 } 72 public class SubClass6<T> : BaseClass6<T>,ISomeInterface6<T> 73 { 74 public override T SomeMethod(T t) 75 { return default(T); } 76 } 77 #endregion 78 79 泛型抽象方法和泛型接口#region 泛型抽象方法和泛型接口 80 //public class Calculator<T> 81 //{ 82 // public T Add(T arg1, T arg2) 83 // { 84 // return arg1 + arg2;//Does not compile 85 // } 86 // //Rest of the methods 87 //} 88 89 public abstract class BaseCalculator<T> 90 { 91 public abstract T Add(T arg1, T arg2); 92 //public abstract T Subtract(T arg1, T arg2); 93 //public abstract T Divide(T arg1, T arg2); 94 //public abstract T Multiply(T arg1, T arg2); 95 } 96 public class MyCalculator : BaseCalculator<int> 97 { 98 public override int Add(int arg1, int arg2) 99 { 100 return arg1 + arg2; 101 } 102 //Rest of the methods 103 } 104 105 public interface ICalculator<T> 106 { 107 T Add(T arg1, T arg2); 108 //Rest of the methods 109 } 110 public class MyCalculator1 : ICalculator<int> 111 { 112 public int Add(int arg1, int arg2) 113 { 114 return arg1 + arg2; 115 } 116 //Rest of the methods 117 } 118 #endregion 119 120} 121 3.泛型方法 1using System; 2using System.Collections.Generic; 3using System.Text; 4 5namespace VS2005Demo2 6{ 7 8 泛型方法#region 泛型方法 9 public class MyClass 10 { 11 public void MyMethod<T>(T t) 12 { } 13 } 14 15 public class Class3 16 { 17 public void Test() 18 { 19 MyClass obj = new MyClass(); 20 obj.MyMethod<int>(3); 21 22 obj.MyMethod(3); 23 } 24 } 25 #endregion 26 27 編譯器無法只根據返回值的類型推斷出類型#region 編譯器無法只根據返回值的類型推斷出類型 28 public class MyClass1 29 { 30 public T MyMethod<T>() 31 { return default(T); } 32 } 33 34 public class Class31 35 { 36 public void Test() 37 { 38 39 MyClass1 obj = new MyClass1(); 40 int number = obj.MyMethod<int>(); 41 } 42 } 43 #endregion 44 45 泛型方法約束#region 泛型方法約束 46 public class Class32 47 { 48 public T MyMethod<T>(T t) where T : IComparable<T> 49 { return default(T); } 50 } 51 #endregion 52 53 泛型虛擬方法#region 泛型虛擬方法 54 public class BaseClass33 55 { 56 public virtual void SomeMethod<T>(T t) 57 { } 58 } 59 public class SubClass33 : BaseClass33 60 { 61 public override void SomeMethod<T>(T t) 62 { 63 base.SomeMethod<T>(t); 64 } 65 } 66 67 public class BaseClass34 68 { 69 public virtual void SomeMethod<T>(T t) where T : new() 70 { } 71 } 72 public class SubClass34 : BaseClass34 73 { 74 public override void SomeMethod<T>(T t)// where T : IComparable<T> 75 { } 76 } 77 78 public class BaseClass35 79 { 80 public virtual void SomeMethod<T>(T t) 81 { } 82 } 83 public class SubClass35 : BaseClass35 84 { 85 public override void SomeMethod<T>(T t) 86 { 87 base.SomeMethod<T>(t); 88 base.SomeMethod(t); 89 } 90 } 91 #endregion 92 93 泛型靜態方法#region 泛型靜態方法 94 public class MyClass36<T> 95 { 96 public static T SomeMethod(T t) 97 { return default(T); } 98 } 99 100 public class Class36 101 { 102 public void Test() 103 { 104 int number = MyClass36<int>.SomeMethod(3); 105 } 106 } 107 108 public class MyClass37<T> 109 { 110 public static T SomeMethod<X>(T t, X x) 111 { return default(T); } 112 } 113 public class Class37 114 { 115 public void Test() 116 { 117 int number = MyClass37<int>.SomeMethod<string>(3, "AAA"); 118 int number1 = MyClass37<int>.SomeMethod(3, "AAA"); 119 } 120 } 121 122 public class MyClass38 123 { 124 public static T SomeMethod<T>(T t) where T : IComparable<T> 125 { return default(T); } 126 } 127 128 #endregion 129} 130 4.泛型委托 1using System; 2using System.Collections.Generic; 3using System.Text; 4 5namespace VS2005Demo2 6{ 7 泛型委托#region 泛型委托 8 public class MyClass40<T> 9 { 10 public delegate void GenericDelegate(T t); 11 public void SomeMethod(T t) 12 { } 13 } 14 15 public class MyClassTest40 16 { 17 public void Tests() 18 { 19 MyClass40<int> obj = new MyClass40<int>(); 20 MyClass40<int>.GenericDelegate del; 21 22 del = new MyClass40<int>.GenericDelegate(obj.SomeMethod); 23 del(3); 24 25 //委托推理 26 del = obj.SomeMethod; 27 28 } 29 } 30 #endregion 31 32 委托泛型參數#region 委托泛型參數 33 public class MyClass41<T> 34 { 35 public delegate void GenericDelegate<X>(T t, X x); 36 } 37 38 //外部委托 39 public delegate void GenericDelegate<T>(T t); 40 41 public class MyClass42 42 { 43 public void SomeMethod(int number) 44 { } 45 } 46 47 public class MyClassTest42 48 { 49 public void Test() 50 { 51 MyClass42 obj = new MyClass42(); 52 GenericDelegate<int> del; 53 //del = new GenericDelegate<int>(obj.SomeMethod); 54 55 del = obj.SomeMethod; 56 del(3); 57 58 } 59 } 60 61 #endregion 62 63 委托泛型參數#region 委托泛型參數 64 public delegate void MyDelegate<T>(T t) where T : IComparable<T>; 65 #endregion 66 67 事件#region 事件 68 69 public delegate void GenericEventHandler<S, A>(S sender, A args); 70 71 public class MyPublisher 72 { 73 public event GenericEventHandler<MyPublisher, EventArgs> MyEvent; 74 public void FireEvent() 75 { 76 MyEvent(this, EventArgs.Empty); 77 } 78 } 79 80 public class MySubscriber<A> //Optional: can be a specific type 81 { 82 public void SomeMethod(MyPublisher sender, A args) 83 { } 84 } 85 public class MyClassTest43 86 { 87 public void Test() 88 { 89 MyPublisher publisher = new MyPublisher(); 90 MySubscriber<EventArgs> subscriber = new MySubscriber<EventArgs>(); 91 publisher.MyEvent += subscriber.SomeMethod; 92 } 93 } 94 #endregion 95}