NET 泛型,详细介绍
今天的文章是因为再给一个朋友讲这个的时候随手记录下整理出来的。说白了就是把前辈们曾经给我吹过的我又吹了出去。
泛型:是c# framework 2.0 时代 加入进来的,可以说对与net开发人员来说泛型是无处不再的,喜欢看源码的同学,可能会有发现,包括mvc里面基本上也是有很多发泛型,还有很多设计模式也需要搭配泛型来实现,包括项目架构
泛型的存在,是代码利用率复用性都大大的提升了,有时候object 也是可以起到相同的作用,为什么使用泛型 为什么不是用obj ,我们来看一下:
下面我们列出两个最基础的方法:
/// <summary> /// 返回int /// </summary> /// <param name="i"></param> /// <returns></returns> public int showint(int i) { return i; } /// <summary> /// 返回string /// </summary> /// <param name="i"></param> /// <returns></returns> public string showstring (string i) { return i; }
上面的两个方法自从参数 进来到参数出去的这一个过程中我们没有进行参数方面的转换,也就是说单纯的针对的参数类型上面我们程序代码是没有损失任何的性能的。一位没有存在拆箱装箱的过程。
我们在看两个方法:我们使用了在c# 1.0 时代就存在的一个类型 是object
/// <summary> /// 返回int /// </summary> /// <param name="i"></param> /// <returns></returns> public int showstring(object i) { return convert.toint32(i); } /// <summary> /// 返回string /// </summary> /// <param name="i"></param> /// <returns></returns> public string showstring(object i) { return i.tostring(); }
这里我们使用的阐述类型是obj ,object 是引用类型,也是所有类型的父类,可以包容所有的类型,但是就单说处理参数类型的时候我们需要去转换一下才能进行使用,在这个转换的过程中我们已经损失了性能,但是使用obj 的时候我们可以和成一个方法减少代码量,提升了代码的复用率。
比如:
/// <summary> /// 返回object /// </summary> /// <param name="i"></param> /// <returns></returns> public object showtype(object i) { return i; }
现在简写成为这样后,我们是一个公用的方法:虽然说内部不用去转换了但是,在调用后,还是需要类型的转换同样的需要损失性能。中间性能之所以会损失是因为obj是引用类型,存放在堆上的,假如说我们传的参数是int或其他的值类型来使用我们的公共方法,就会进行一次包装的过程,把存放在栈里面的值类型移动包装成为引用类型存放到堆里面,使参数符合当前方法的类型,这个过成也就是装箱(需要重新分配内存),但是我们在使用的时候,又需要把他拿出来进行一下装换转换为值类型,这个过程又称为拆箱,
我们在来使用一个方法:使用 2.0时代出现的泛型:
/// <summary> /// 返回 t /// </summary> /// <param name="parameter"></param> /// <returns></returns> public t show<s>(t parameter) { return parameter; }
为什么会使用泛型 是因为泛型方法再调用的时候有延时声明的功能这里的延时声明式只参数,泛型里面的 t ,其实咱们也可以理解为 占位符具体为谁占位的,等到调用的时候才会知道。
如下:
int parameter = 0; //在调用的时候声明参数类型 parameter = new common().show<int>(parameter); //如果调用的时候不去声明的话,jit编译的时候野会帮我们自动计算 parameter = new common().show(parameter);
这个时候不会损耗什么性能。延时声明也是咱们在进行框架设计的时候常用的一种思想,提高框架的性能。泛型不只是可以声明泛型方法:
泛型类:
/// <summary> /// curd 操作类 /// </summary> /// <typeparam name="t"></typeparam> public class conmonclass<t> { public void add(t s) { }; public void update(t s) { }; public void del(t s) { }; public void select(t s) { }; }
这样使用的话,在咱们真正的项目,我们可以把某些基础的操作用一个类去搞定,使用的时候调用就是了,减少代码的冗余,增加复用性,重用率。
泛型接口:
/// <summary> /// curd 操作接口类 /// </summary> /// <typeparam name="t"></typeparam> public interface conmoninterface<t> { t add(t s); t update(t s); t del(t s); t select(t s); }
泛型委托:
//泛型委托 public delegate t gethandler<t>();
我想以上的操作在我们开发项目的时候会经常见到,或使用到
以上代码需要我们注意的时候,泛型类不能被继承,如果想要继承的话需要在继承的时候,给我们的不确定参数确定下参数类型。包括泛型接口也是一样的。
如下:
public class son : conmonclass<common> {}; /// <summary> /// 实现泛型接口 /// </summary> public class soninterface : conmoninterface<common> { public common add(common s) { throw new notimplementedexception(); } public common del(common s) { throw new notimplementedexception(); } public common select(common s) { throw new notimplementedexception(); } public common update(common s) { throw new notimplementedexception(); } }
如果说不指定泛型类型的参数类型式其实我们一样是可以继承的。需用继承者同样是泛型的。
建议:长期使用net的同学我想我们需要加强一下泛型的认识了,因为在netcore中常常会使用依赖注入,在使用泛型类的时候我们可能会多少有点麻烦的,泛型方法相对来说要简单的,如果说要想让我们的框架实现高度的内聚,大家需要多多理解。
泛型的约束,多重约束相当重要,代表我们是否能很好的利用泛型。
泛型的约束类型大概分为如下几种:
引用类型约束: |
表明泛型参数只能是引用类型的: |
值类型约束: |
表明泛型参数只能是值类型的: |
无参数构造函数约束: |
泛型是可以实例化的。 |
基类约束 |
必须满足基类中的某些属性 |
接口约束 |
必须满足接口中的某些属性 |
具体的就不代码了。
有不足之处 希望大家指出相互学习,
本文原创:转载请注明出处 谢谢!