标签:
泛型是CLR和编程语言提供的一种特殊机制,它用于满足“算法重用” 。
可以想象一下一个只有操作的参数的数据类型不同的策略模式,完全可以用泛型来化为一个函数。
以下是它的优势:
这就是为什么List<T>淘汰了ArrayList的原因,特别是在进行值类型操作时,因为装箱拆箱过多而差距很大。
约定:泛型参数要么为T要么以大写T开头,例如List<T>。
FCL中的泛型
System.Collections.Generic和System.Collections.ObjectModel命名空间中提供了多个泛型集合类和接口。
System.Collections.Concurrent命名空间则提供线程安全的泛型集合类。
System.Array类则提供了大量的静态泛型方法。
泛型的基础结构
.net 2.0才有泛型。
委托和接口的逆变和协变泛型类型实参
泛型委托和接口的每个泛型类型参数都可标记为协变量和逆变量,利用此功能可实现相同类型但实参类型不同的委托和接口的相互转换。(很绕,不明白可以看下面)
举个例子
public class 基类 { } public class 派生类 : 基类 { } public class Test{ public delegate TResult MyFunc<in T1, out TResult, T2>(T1 a, T2 b);//第一个为逆变量,第二个为协变量,第三个为不变量 void show() { MyFunc<基类, 基类, 基类> fn1 = null; //以下注释为我自己的理解方式,只是为了方便理解而已 MyFunc<派生类, 基类, 基类> fn2 = fn1;//MyFunc<派生类, 派生类, 基类> fn2 = fn1;转换错误 MyFunc<基类, Object, 基类> fn3 = fn1;//MyFunc<Object, Object, 基类> fn3 = fn1;转换错误 MyFunc<派生类, Object, 基类> fn4 = fn1; } }
依然很绕,实际上不懂也没关系,转换不了编译器自然会提示。了解有这个东西就行了,也建议用int和out指定泛型委托的类型变量。更多的时候我们会用自带的泛型委托Action和Func,这两个泛型委托的参数都用到in和out。
关于泛型方法的类型推断
void Go() { String s1 = "213"; Object s2 = "123"; Show(s1, s2);//不指定Show<T>的T的玩法就叫类型推断,类型推断通过传入的变量s1和变量s2的变量类型来推断,而不是实际类型。因为这里两个变量类型不同,所以函数编译不通过。 } void Show<T>(T a,T b) { }
约束
泛型的约束是一个很有意思的事情。
void Show<T>(T a,T b) where T :IList { }
比如上面这个函数,约束传入的类型T必须实现了IList接口。
通过约束可以限制传入的类型,然而正式因为提供了这层约束,保证了传入的类型都实现了IList接口,我们就可以使用IList的各种方法了。
约束分类:
可验证性
以下几种情况因为代码不可验证是否合法,所以将报错:
void Show<T>(T obj){ string a=(string)obj; //出错 }
void Show<T>(T obj) { string a = obj as string;//对于string而言,其实这里用ToString方法可能更恰当一点 }
值类型可以先强制转换为object,再转为具体的值类型。然而我认为这样的代码还是需要开箱装箱的,也许可以考虑修改下算法。
标签:
原文地址:http://www.cnblogs.com/vvjiang/p/5290159.html