白话泛型

来源:互联网 发布:floor php 编辑:程序博客网 时间:2024/05/16 19:39
泛型 一、什么是泛型? 通过泛型可以定义类型安全类,而不会损害类型安全、性能或工作效率 二、实例化泛型 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[] m_Items; public void Push(T item) {...} public T Pop() {...} } Stack stack = new Stack (); stack.Push(1); int number = (int)stack.Pop(); 三:泛型的好处 1、一次性的开发、测试和部署代码,通过任何类型来重用它 2、编译器支持和类型安全 3、不会强行对值类型进行装箱和取消装箱,或者对引用类型进行向下强制类型转换,所以性能得到显著提高。 注:值类型大概可以提高200%,引用类型大概为100% 四:多个泛型 1、单个类型可以定义多个泛型 五:泛型别名 1、在文件头部使用using 为特定类型取别名,别名作用范围是整个文件 2、例子 using List = LinkedList ; class ListClient { static void Main(string[] args) { List list = new List(); list.AddHead(123, "AAA "); } } 五:泛型约束 (1)、派生约束 如: public class LinkedList where K:IComparable { T Find(K key) { if (str.Key.CompareTo(key) == 0)//只有实现这个接口才可比较 } } 注意: 1、所有的派生约束必须放在类的实际派生列表之后 如:public class LinkedList :IEnumerable where K:IComparable {...} 2、一个泛型参数上可以约束多个接口(用逗号分隔) public class LinkedList where K:IComparable ,IConvertible 3、在一个约束中最多只能使用一个基类 4、约束的基类不能是密封类或静态类 5、不能将System.Delegate或System.Array约束为基类 6、可以同时约束一个基类以及一个或多个接口,但是该基类必须首先出现在派生约束列表中。 7、C#允许你将另一个泛型参数指定为约束 public class MyClass where T:U {...} 8、可以自己定义基类或接口进行泛型约束 9、自定义的接口或基类必须与泛型具有一致的可见性 (2)、构造函数约束 如: class Node 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 where T:BaseClass,IS { void SomeMethod(T t) { IS obj1 = t; BaseClass obj2 = t; object obj3 = t; } } 2、编译器允许你将泛型参数显示强制转换到其他任何借口,但不能将其转换到类 interface IS{...} class SomeClass{...} class MyClass //没有约束 { void SomeMethod(T t) { IS obj1 = (IS)t; //可以 SomeClass obj2 = (SomeClass)t //不可以 } } 3、可以使用临时的Object变量,将泛型参数强制转换到其他任何类型 class SomeClass{...} class MyClass { void SomeMethod(T t) { object temp = t; SomeClass obj = (SomeClass)temp;//可以 } } 注意:这里只是告诉你这样写是可以的,但是要不要这样写?不要这样写,因为如果t确实没有继承SomeClass编译没错但是运行就会出错 4、解决上面强制转换问题,可以使用is和as运算符进行判断 public class MyClass { public void SomeMethod { if (t is int ){...} if (t is LinkedList ){...} //如果泛型参数的类型是所查询的类型,则is运算符返回true string str = t as string; //如果这写类型兼容,则as将执行强制类型转换,否则将返回null if (str != null){...} LinkedList list = t as LinkedList ; if (list != null){...} } } 七:继承和泛型 1、在从泛型基类派生,可以提供类型实参,而不是基类泛型参数 public class BaseClass {...} public class SubClass:BaseClass 2、如果子类是泛型,而非具体的类型实参,则可以使用子类泛型参数作为泛型基类的指定类型 public class BaseClass {...} public class SubClass :BaseClass {...} 3、在使用子类泛型参数时,必须在子类级别重复在基类级别规定的任何约束 4、基类可以定义其签名使用泛型参数的虚礼方法,在重写它们时,子类必须在方法签名中提供相应的类型。 如: public class BaseClass { public virtual T SomeMethod() {...} } public class SubClass:BaseClass { public override int SomeMethod() {...} } 5、如果该子类是泛型,则它还可以在重写时使用它自己的泛型参数 public class SubClass :BaseClass { public override T SomeMethod() {...} } 6、你可以定义泛型接口、泛型抽象类,甚至泛型抽象方法。 7、不能对泛型参数使用+或+=之类的运算符 public class Calculator { public T Add (T arg1,T arg2) { return arg1 + arg2;//错误 } } 但是我们可以通过泛型抽象类、接口来实现在个功能,因为实现泛型抽象类、接口我们就已经明确传一个参数了,就可以执行诸如+这样的操作。 八:泛型方法 1、方法可以定义特定于其执行范围的泛型参数 public class MyClass { public void MyMethod (X x) {...} } 2、即使各包含类根本不使用泛型,你也可以定义方法特定的泛型参数 public class MyClass { public void MyMethod (T t) {...} } 注意:该功能只使用于方法,属性,索引器只能使用在类的作用范围中定义的泛型参数。 3、调用泛型方法 MyClass obj = new MyClass(); obj.MyMethod (3); 也可以这样: MyClass obj = new MyClass(); obj.MyMethod(3); //该功能称为泛型推理 4、泛型方法也可以有自己的泛型参数约束 pubic class MyClass { public void SomeMethod (T t) where T:IComparable {...} } 5、子类方法实现不能重复在父级别出现的约束 public class BaseClass { public virtual void SomeMethod (T t)where T:new() {...} } pubic class SubClass:BaseClass { public override void SomeMethod (T t)//不能再有约束 {...} } 6、静态方法 静态方法可以定义特定的泛型参数和约束 public class MyClass { public static T SomeMethod (T t,X x) {...} } int number = MyClass .SomeMethod (3, "AAA "); 或者:int mumber = MyClass .SomeMethod(3, "AAA "); 九:泛型委托 1、在某个类中定义的委托可以利用该类的泛型参数 2、委托也可以定义自己的泛型参数
原创粉丝点击