再次接触"泛型"

来源:互联网 发布:js点击事件用法 编辑:程序博客网 时间:2024/05/10 09:22
【学习背景】泛型,大家对这个词都不陌生了。很多时候,我们也在各个项目中经常见到和使用过。但对于它的一些理论知识,想必大家还是有所欠缺的,下面便是自己的补充学习过程。【学习阶梯】一.什么是泛型当一个方法,需要被重复利用多次,但方法的参数类型并不相同,如果要想使用此方法,则需要复制此方法代码,加上不同的参数类型。为了解决这一问题,在方法中传入通用的参数类型,便是泛型。二.为什么要使用泛型下面以一个"栈"的代码实例来看:
public class Stack    {        private int[] m_item;        public int Pop(){...}        public void Push(int item){...} //参数类型为int型        public Stack(int i)  //传入的参数类型必须为int型        {            this.m_item = new int[i];        }}
上面的代码,栈中的参数类型为int型,如果现在需要将string类型的参数传进去,就需要把上面的方法复制一遍,将参数修改,改成push(string item).这样下去,只要参数类型不相同,就需要重复写一遍相同的代码。所以,为了提高代码的复用性,就需要对传递的参数进行抽象,自然想到了object类型。

三.使用object类型参数,修改以上代码

public class Stack    {        private int[] m_item;        public int Pop(){...}        public void Push(obj item){...}  //参数类型为object类型        public Stack(int i)  //传入的参数为int类型        {            this.m_item = new int[i];        }}<span style="font-family:KaiTi_GB2312;font-size:18px;"></span>
这样的方法很好的解决了参数类型不同的问题,但这样的方法并不是十全十美的。下面就先看看使用object类型作为参数的优缺点:
优点:实现了代码的复用性,提高了代码的灵活性。缺点:当处理值类型数据时,使用此代码需要经过一个装箱和拆箱的操作。数据量大的时候,性能损失严重。当处理引用类型时,不需要进行装箱操作,但需要将数据进行强制转换,增加了处理器的负担。PS:装箱:将值类型转换为引用类型的过程。      拆箱:将引用类型转换为值类型的过程。四.使用泛型下面是用泛型来重写上面的栈,用一个通用的数据类型T来作为一个占位符,等待在实例化时用一个实际的类型来代替。

public class Stack<T>    {        private T[] m_item;        public T Pop(){...}        public void Push(T item){...}  //通用数据类型T作为参数类型        public Stack(int i)  //传入int类型的参数        {            this.m_item = new T[i];        }}
 类的写法不变,只是引入了通用数据类型T就可以适用于任何数据类型,并且类型安全的。
      下面分别传入int类型的参数和string类型的参数调用方法:

//实例化只能保存int类型的类Stack<int> a = new Stack<int>(100);      a.Push(10);      a.Push("8888"); //这一行编译不通过,因为类a只接收int类型的数据      int x = a.Pop(); //实例化只能保存string类型的类Stack<string> b = new Stack<string>(100);      b.Push(10);    //这一行编译不通过,因为类b只接收string类型的数据      b.Push("8888");string y = b.Pop();<span style="font-family:KaiTi_GB2312;font-size:18px;"></span>
五.使用泛型的好处
1.他是类型安全的。实例化了int类型的栈,就不能处理string类型的数据,其他数据类型也一样。2.无需装箱和折箱。这个类在实例化时,按照所传入的数据类型生成本地代码,本地代码数据类型已确定,所以无需装箱和折箱。3.无需类型转换。六.泛型类中的约束1.数据类型的约束通用数据类型T就适合所有的数据类型吗?这个问题是值得思考的。答案是不一定的。所以,泛型中也需要对数据类型进行约束,约束的方式是指定T的祖先,即集成的接口或类。因为C#的单继承性,所以,约束可以有多个接口,但最多只能有一个类,并且类必须在接口之前,代码如下:

public class Node<T, V> where T : Stack, IComparable        where V: Stack    {...}<span style="font-family:KaiTi_GB2312;"></span>

相信大家对此代码并不会感觉陌生,以上泛型类的约束表明,T是必须从Stack和IComparable集成,V必须是Stack或从Stack继承,否则将无法通过编译器的类型检查,编译失败。2.实例化的约束对T进行实例化,因为类中不知道类T有哪些构造函数,为了解决这一问题,需要用到new约束,代码如下:

public class Node<T, V> where T : Stack, new()        where V: IComparable<span style="font-family:KaiTi_GB2312;"></span>

3.关键字的约束C#中数据类型有两大类:引用类型和值类型。在泛型的约束中,我们可以大范围地限制类型T必须是引用类型或必须是值类型,分别对应关键字class和struct。代码如下:

public class Node<T, V> where T : class        where V: struct<span style="font-family:KaiTi_GB2312;font-size:18px;"></span>

七.泛型方法泛型不仅可以用在类中,也可以用在方法中,称为泛型方法。大家应该都还记得,我们在机房收费系统中,写过一个公共的方法,也就是将DataTable转换为list集合,那便是我们自己封装好的一个泛型方法。【学习总结】这一次的学习,主要是丰富了关于泛型的理论知识。对于泛型在ITOO项目中的应用,主要是出现在底层封装好的方法中。因为我们并不知道方法会传入怎么类型的参数,所以利用通用数据类型T表示,加上泛型各种约束,也就成了。最后,简言之,泛型可以提高性能、类型安全和质量,减少重复性的编程任务,简化总体编程模型。

0 0
原创粉丝点击