使用泛型的好处是“代码重用”,极大的提升了开发效率,泛型为开发者提供了如下优点:c++
1,源代码保护 算法的源代码不须要提供给使用泛型算法的开发人员,使用c++模板的泛型技术须要提供。(目前c++模板的泛型技术了解较少)算法
2,类型安全 给泛型算法指定类型时,编译器能理解开发者意图,只有兼容类型能经过,不兼容的时候编译时候会报错。安全
3,更清晰的代码 因为编译器强制类型的安全性,减小源代码中必须进行的转型次数,使得代码容易维护和编写。例如:DateTime dt=dtList[0];从DateTime的集合中按照索引取出来的值能够直接赋值给DateTime类型,不须要转型。ide
4,更佳的性能 在操做值类型时候,非泛型集合会形成装箱、拆箱操做,会形成托管堆上的内存分配,会形成频繁的垃圾回收,影响性能。性能
补充:对于泛型方法,约束父类类型,与参数直接传递父类,在没有返回值的状况下是没有区别的,假若有须要返回传入的类型,则用泛型方法比较合适,由于经过泛型方法返回的类型不须要通过类型转换 http://bbs.csdn.net/topics/380050195优化
1 public class AA{} 2 public class BB:AA{} 3 4 5 public void GetText<T>(T t) where T:AA 6 { 7 } 8 与 9 public void GetText(AA x) 10 {}之间是等效的,没有区别。 11 12 13 public T GetText<T>(T t) where T:AA 14 { 15 } 16 public AA GetText(AA x) 17 在调用的地方是有区别的 18 19 BB b=new BB(); 20 var rtGetText=GetText<BB>(b); 21 var rtGetText2=(BB)GetText(B);//须要进行一次类型转换
具备泛型类型参数的类型称为开放类型。ui
不能建立实例。例如Dictionary<,>,没有指定参数,目前尚不清楚这个开放类型有什么用。this
全部类型实参传递的都是实际数据类型为封闭类型。spa
使用约束没法将类型实参限制为某一类型,能够用一个静态构造器来保证类型。以下.net
internal sealed class GenericTypeThatRequiresAnEnum<T>{ static GenericTypeThatRequiresAnEnum(){ if(!typeof(T).IsEnum){ throw new ArgumentException("T must be an enumerated type"); } } }
泛型类型仍然是类型,它能从其余任何类型派生。
public class Node1<T> { public T m_data; public Node1<T> m_next; public Node1(T data) : this(data, null) { } public Node1(T data, Node1<T> next) { m_data = data; m_next = next; } public override string ToString() { // ABC return m_data.ToString()+((m_next!=null)?m_next.ToString():null); } }
上面例子必须是相同数据类型下使用,加入链表须要多个m_data为多种类型的时候这种结构将没法知足,这时候咱们能够考虑抽出一个非泛型的基类,这样继承的泛型就能够指定多种类型。这是一个泛型应用的技巧。
public class Node2 { protected Node2 m_next; public Node2(Node2 next) { m_next = next; } } public class TypeNode<T> : Node2 { public T m_data; public TypeNode(T data,Node2 next):base(next){ m_data = data; } public TypeNode(T data):this(data,null){ } public override string ToString() { // Tody is 时间。 return m_data.ToString() + ((m_next != null) ? m_next.ToString() : null); } }
这种性质不常常用,这里简单记一下只当了解。
简化泛型的写法多封装一层去除"<"">"。
class DateTimeList:List<DateTime>{
//这里不须要放入任何代码。
}
这样使用的时候就没有<,>符号了。
DateTimeList dt=new DateTimeList();
这只是表面方便了,绝对不要单纯出于加强代码可读性目的定义一个新类,事实上也不会这么作,可是这样写会丧失同一性和相等性,以下代码为Flase
Boolean sameType=(typeof(List<DateTime>)==typeof(DateTimeList));
能够经过使用using指令弥补相等性,添加以下结果为True;
using DateTimeList=System.Collections.Generic.List<System.DateTime>;
使用泛型类型参数的一个方法在JIT(即时编译)编译时,Clr获取方法的IL,用指定的实参进行替换,建立恰当的本地代码,缺点是CLR要为每种不一样的方法、类型组合生成本地代码,可能形成应用程序集显著增大,损坏性能,称之为 代码爆炸。
可是CRL内建了一些优化措施,缓解代码爆炸。全部程序集使用List<DateTime>时候,只会生成一次,认为全部引用类型实参都是彻底相同,List<String>和List<Stream>能够公用,之因此会这样,是由于全部引用类型的实参或者变量实际都是指向堆上的对象指针,而指针所有都是以相同的方式来操做。
泛型接口的一个例子是IComparable接口,在接口里详细写
建议使用泛型的Action和Func委托,会在之后的委托中细说
不变量(invariant)表示泛型类型不可变。
逆变量(contravariant)表示泛型类型参数能够从一个基类更改成该类的派生类,用in关键字标记,只出如今输入位置。
协变量(covariant) 表示泛型类型能够从一个派生类更改成它的基类型,用out关键字标记,只出如今输出位置。
public delegate TResult Func<in T,out TResult>(T arg);
Func<object,ArgumentException> fn1=null;
func<string,Exception> fn2=fn1;//这里不须要显示转换,由于逆变量,协变量
调用委托Exception e=fn2("");
使用要获取泛型参数和返回值的委托时,建议尽可能使用in和out关键字,由于不会有不良反应。
泛型接口和泛型委托同样也能够用out和in。
用一个例子介绍下泛型的定义,下面一个类型定义了一个类型参数,一个方法定义了它本身的专用类型参数。
class GenericType<T>{ private T m_value; public GenericType(T value){m_value=value;} public TOutput Coverter(TOutput)(){ TOutput result=(TOutput)Convert.ChangeType(m_value,typeof(TOutput )); return result; } }
下面写一个比较经典经常使用的泛型方法,2个参数互换
private static void Swap<T>(ref T o1,ref T o2){ T temp=o1; o1=o2; o2=temp; }
确保使用当前泛型是本身想要的类型。
例如以下方法,在类型没有提供CompareTo方法时候会报错。
private static T Min<T>(T o1,To2){
if(o1.CompareTo(o2)<0)
return o1;
return o2;
}
这个时候咱们就须要在该泛型方法添加泛型约束。
private static T Min<T>(T o1,To2) where T:IComparable<T>{
if(o1.CompareTo(o2)<0)
return o1;
return o2;
}
泛型约束主要分为3种。
1,主要约束 主要约束能够是一个引用类型,实参必须与约束相同或者派生,
例如where T:Stream ,使用该泛型方法必须是Stream 类型或者其派生类型。
where T:Class,使用该泛型方法必须是引用类型。
2,次要约束 次要约束表明的是一个借口类型,指定的参数必须实现全部接口约束例如 where T:IComparable<T>
3,构造器约束 指定的实参必须实现公共无参构造器的一个非抽象类型where T:New()
下面是项目中用到的一个泛型方法,模板反序列化。使用了Newtonsoft.Json
public T GetTemplateData<T>() where T : TemplateData { if (!string.IsNullOrEmpty(TemplateDataJsonStr)) { T obj = (T)JsonConvert.DeserializeObject(TemplateDataJsonStr, typeof(T)); obj.CheckField(); return obj; } else return null; } public void SetTemplateData(TemplateData templateData) { TemplateDataJsonStr= JsonConvert.SerializeObject(templateData); }