我们在编写C#程序的时候,经常遇到两个模块的功能非常相似,只是一个是处理int类型,另一个是处理string类型,或者是其他自定义的数据类型,但我们没有其他的解决方案,只能各自写多个方法处理每个数据类型,因为方法的参数类型不同。那么是否有一个办法,在方法中传入通用的数据类型,这样就可以合并代码了。C#泛型应用正是为解决这个问题的。C#泛型应用可以解决什么样的问题呢?我们先看下面的代码,代码中省略了一些内容,但功能是实现一个栈,这个栈只能处理int数据类型:
- public class Stack
- {
- private int[] m_item;
- public int pop() {}
- public void push(int item) {}
- public Stack(int i) {this.m_item = new int[i]; }
- }
上面的代码运行得很好,但是,如果我们需要一个栈来保存string类型的数据时呢?或许很多人都会想到把上面的代码copy一份,把int改成string就可以了。当然,这样做,是没问题的,但是如果以后需要long,Node类型的栈该怎么办?继续复制?这里有种折衷的办法,是使用一个通用的数据类型object来实现这个栈:
- public class Stack
- {
- private object[] m_item;
- public object pop() {}
- public void push() {}
- public Stack(int o){this.m_item = new object [o]}
- }
虽然这个栈很灵活,可以接收任何数据类型。但全面地说,也不是没有缺陷的,主要表现在:
◆当Stack处理值类型时,会出现装箱,拆箱操作,这将在托管堆上分配和回收大量的变量,若数据量大,则性能损失非常严重。
◆在处理引用类型时,虽然没有装箱和拆箱操作,但将用到数据类型的强制转换操作,增加了处理器的负担。
在数据类型的强制转换上还有更严重的问题,如下:
- Node1 x = new Node1();
- stack.push(x);
- Node2 y = (Node2)stack.pop();
上面的代码在编译时是没有问题的,但是由于push了一个Node1类型的数据,但在pop时却要求转换为Node2类型,这将出现程序运行时的类型转换异常,但却逃离了编译器的检查。
针对object类型栈的问题,我们引入泛型,他可以很优雅地解决这些问题。泛型用一个通过的数据类型T来代替object,在类实例化时指定T的类型,运行时(Runtime)自动编译为本地代码,运行效率和代码质量都有很大的提高,并且保证数据类型安全。
C# 泛型应用实例:
下面是使用泛型来重写上面的栈,用一个通用的数据类型T来作为一个占位符,等待在实例化时用一个实际的类型来替换。如下:
- public class Stack﹤T﹥
- {
- private T[] m_item;
- public T pop() {}
- public void push(T item) {}
- public Stack(int i)
- {
- this.m_item = new T[i];
- }
- }
类的写法不变,只是引入了通用数据类型T就可以适用于任何数据类型,并且类型安全的。这个类的调用方法:
- Stack﹤int﹥ a = new Stack﹤int﹥(100);
- a.push(10);
- a.push("10"); //这里编译不通过,因为类a只接收int类型的数据
- int x = a.pop();
- Stack﹤string﹥ b = new Stack﹤string﹥(100);
- b.push(10); //这里编译不通过,因为类b只接收string类型的数据库
- b.push("10");
- string y = b.pop();
这个类和object实现的类有截然不同的区别:
1. 他是类型安全的。实例化了int类型的栈,就不能处理string类型的数据,其他数据类型也一样;
2. 无需装箱和拆箱。这个类在实例化时,按照锁传入的数据类型生成本地代码,本地代码数据类型已确定,所以无需装箱和拆箱。
3. 无需数据类型转换。
C# 泛型应用心得的一些总结就向你介绍到这里,希望对你了解和学习C# 泛型有所帮助。
【编辑推荐】