.NET泛型01,为什么需要泛型,泛型基本语法

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

.NET泛型或许是借鉴于C++泛型模版,借助它可以实现对类型的抽象化、泛型处理,实现了类型和方法之间的解耦。一个最经典的运用是在三层架构中,针对不同的领域模型,在基接口、基类中实现针对各个领域模型的泛型处理。

本篇主要包括:

■ 为什么需要泛型

※ 不用泛型

※ 使用泛型

※ 泛型的运行时本质

■ 泛型语法

■ 典型的泛型类

为什么需要泛型

不用泛型

来看一个比较类型的方法。

publicclassCalculator

{publicstaticboolAreEqual(intvalue1,intvalue2)

{returnvalue1 ==value2;

}

}

在客户端调用。

classPRogram

{staticvoidMain(string[] args)

{boolresult = Calculator.AreEqual(1,2);if(result)

{

Console.WriteLine("相等");

}else{

Console.WriteLine("不等");

}

Console.ReadKey();

}

}

运行结果:不等

不用泛型的缺点一:不是类型安全

如果我们想使用现在的方法来比较字符串类型。

boolresult = Calculator.AreEqual("A","B");

这时,看到编译器报错。从这点来看,AreEqual()方法不是类型安全的方法,当输入string类型,编译器就会报错。

如果把AreEqual()方法的参数类型改成object,编译器就不再报错。

publicclassCalculator

{publicstaticboolAreEqual(objectvalue1,objectvalue2)

{returnvalue1 ==value2;

}

}

以上,运行也正常。

不用泛型的缺点二:装箱与拆箱导致性能降低

现在,对于AreEqual(object value1, object value2),从方法本身来讲是没有问题的,但在客户端调用的时候,比如我们还是想比较值类型。

boolresult = Calculator.AreEqual(1,2);

在运行时,当整型值类型参数1和2传递、赋值给AreEqual(object value1, object value2)中的引用类型参数value1和value2的时候,发生了一次"装箱"操作。而当把引用类型转换成值类型的时候,又会发生一次"拆箱"操作,这导致性能的降低。

使用泛型

把AreEqual()改成泛型方法。

publicclassCalculator

{publicstaticboolAreEqual<T>(T value1, T value2)

{returnvalue1.Equals(value2);

}

}

于是,在客户端可以这样:

boolresult = Calculator.AreEqual<string>("A","A");boolresult = Calculator.AreEqual<int>(5,3);

由此,使用泛型的好处有:

1、实现了方法和类型的解耦。

2、不会造成类型转换,规避了因装箱于拆箱引起的性能问题。

3、泛型保证了类型的绝对安全。

当然,还可以把T的位置放在类上:

publicclassCalculator<T>{publicstaticboolAreEqual(T value1, T value2)

{returnvalue1.Equals(value2);

}

}

然后这样使用:

boolresult = Calculator<string>.AreEqual("A","A");boolresult = Calculator<int.AreEqual(1,2);

泛型的运行时本质

CLR中有专门的IL指令支持泛型操作。

→初次编译时,生成IL代码和元数据,T只是类型占位符,在编译时不进行实例化

→JIT编译时,以实际类型替换元数据中的T占位符

→将元数据转换为本地代码

泛型语法

classMyArray<T>whereT : Student,new()

{privateT[] _items;publicT myData;publicMyArray()

{

myData=default(T);

}publicvoidAdd(T item)

{}

}

创建泛型实例要指定实际的数据类型:

MyArray<Int32> myArr = new MyArray<Int32>();

值类型的默认值为0,引用类型的默认值为null,使用泛型默认值:

myData = default(T);

泛型约束:

T : 基类名,表示必须是基类名的派生类

T :new(), 表示必须具有无参构造函数,new()约束必须放在最后面

T :struct, 表示必须是值类型

T :class, 表示必须是引用类型

T :接口名,表示必须实现该接口,或实现该接口的接口

泛型类本质上仍然是一个类,依然可以继承:

internalclassGenericeComparer<T> : Comparer<T>whereT : IComparable<T>classMyArray<T> : ArrayList

典型的泛型类

在System.Collections.Generic命名空间和System.Collections.ObjectModel中,定义了不同的泛型类和泛型接口,这些泛型多为集合类。

List<T> 对应ArrayList集合类

SortedList<TKey, TValue> 对应SortedList集合类

Queue<T> 先进先出的集合类

Stack<T> 后进先出的集合类

Collection<T> 自定义泛型集合的基类

Dictionary<TKey, TValue> 对应于Hashtable集合类

参考资料:

《你必须知道的.NET(第2版)》,作者王涛。

".NET泛型"系列包括:

.NET泛型01,为什么需要泛型,泛型基本语法.NET泛型02,泛型的使用.NET泛型03,泛型类型的转换,协变和逆变.NET泛型04,使用Lazy<T>实现延迟加载

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航