c#泛型
写在前面:此随笔仅仅是作为个人学习总结,有不对的地方,请各位前辈指正O(∩_∩)O........
一: 什么是泛型
泛型是c#2.0之后新特性,是一种语法糖.将大量的安全检查从执行期转移至了编译期,使类型参数化.大至思想就是编译时期确定其类型,延迟思想.
二: 使用泛型
1: 泛型的出现,提高了性能,那么没有泛型之前是一个什么样子呢?
举个例子:
比如,我们要分别输出一个数字和字符串,我们需要像这样写:
/// <summary> /// 打印数字 /// </summary> /// <param name="i"></param> public void PrintInt(int i) { Console.WriteLine("this is a method print number: {0},this type is {1}", i, i.GetType()); } /// <summary> /// 打印字符串 /// </summary> /// <param name="s"></param> public void PrintString(string s) { Console.WriteLine("this is a method print string: {0},this type is {1}",s,s.GetType()); }
可以看到上面两个方法内部都是基本上相同的.那聪明的程序员们就思考怎么可以优化上面的代码.我们可以知道object是所有的父类,那么就有了下面这一个优化之后的代码:
public void PrintObject(object o) { Console.WriteLine("this is a method print object: {0},this type is {1}", o,o.GetType()); }
这样我们就把两个方法优化成了一个方法,达到了一样的目的.接下来问题又来了,现在这样的写法,就又存在了一个问题,就是装箱和拆箱的问题,一次两个装箱拆箱我们似乎可以忽略,但是大量的进行装箱和拆箱那就太损失性能啦.
由于这样那样的问题,聪明的程序员就思考,怎么能够避免装箱拆箱问题,又能将代码变得简单可读的,就这样泛型就随之产生啦.来看看有了泛型之后上面的代码又会变成什么样呢?
/// <summary> /// 泛型方法 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="param"></param> public void PrintGenerics<T>(T param) { Console.WriteLine("this is a generics method print param: {0},this type is {1}", param,param.GetType()); } //使用 common.PrintGenerics<int>(1);
common.PrintGenerics(1);
这样就是一个泛型方法了.现在有几个疑问就是:
a: T是一个什么东西呢,以前都没有见过?
答: 从文档注释,对T的解释,T是一个类型参数,需要我们传入具体的类型实参,T实际上是一个占位符,在编译之后就变成了 `1这样一个占位符.
b: 在调用的时候为什么可以省略<int>呢?
答: 编译器会根据传入的参数,来推断出具体的类型
c: 这种方式为什么就比通过object来输出好呢?
答: 从上面的解释可以知道object是存在装箱和拆箱问题的,会损耗性能.而泛型就不存在装箱和拆箱的问题,因为从前面可以知道泛型是在编译的时候才知道类型,实际上编译器在我们不知道的时候根据他的类型创建了相应数据类型的副本方法,比如:
common.PrintGenerics<int>(1); //创建的副本方法类似于 public void PrintInt(int i) { Console.WriteLine("this is a method print number: {0},this type is {1}", i, i.GetType()); }
这样就不存在值类型到引用类型的转换.
2: 泛型还有哪些应用呢?
泛型类,泛型接口,泛型方法,泛型返回,泛型约束
2.1: 泛型约束:
泛型约束是个什么东西呢?大概就是让参数满足它的条件(2333,解释不来 =_=||)
就比如:
common.PrintGenerics<Person>(new Person());
我们此时的参数是一个person对象,那么我们想输出person的名字,但是我们发现这样是没有出现param.Name的.
这是为什么呢?
因为此时我们的参数没有添加约束,就相当于是一个object,那object里面有name属性吗?很显然是没有的.举个例子:就像我们让一个"str"字符串输出它的name属性,是不现实的,因为没有.
这个时候我们的约束就该上场啦
public void PrintGenericsPerson<T>(T p) where T: Person { Console.WriteLine("my name is :"+p.Name); }
泛型约束通过where来实现.
那么疑问又来了:
a: 约束后的效果是什么样呢?
答: 现在我们就只能person类型以及它的子类型来作为参数啦.
b: 这样写和直接规定它的参数类型为person有什么区别吗?
答: 个人认为一般在确定是person类型的时候,就不会在传入其子类型作为参数了,在做架构方面可能非常有用(个人理解不是很透彻)
c: 还有其他的约束吗?
答: class: 表示约束为引用类型(此时传一个数字就会出错). struct: 表示约束为值类型(DateTime为值类型). new(): 表示约束参数要有无参数的构造函数.等等
2.2: 泛型的静态成员变量
静态成员在相同的封闭类间共享.不同的封闭类间不共享
开放类型:泛型类型没有指定具体的数据类型.
封闭类型:泛型类型指定了具体的数据类型.
2.3: 泛型方法的重载
a: 是在实例方法被调用的时候检查重载是否混淆,而不是在泛型类本身编译时检查
b: 当一般方法与泛型方法具有相同的签名时,会覆盖掉泛型方法,而使用一般的方法.