、 介绍
泛型现在在任何种语言中都被认为是个高级强有力术语当我在C中第次接触模板时我对的有些疑惑的后我读了Bjarne StroustropThe Design and Evolution of C才发现模板使用就象C中宏和用的来取代简单串替换模板样容易其实模板和泛型是相同东西-尽管它们实现稍微区别
C#泛型支持在使用点处才定义算法及其数据类型在C#些早期版本中我们可以证明没有泛型也可以工作每种类型都是派生于个公共基类型-object这意味着员可以基于object类型定义个栈类并且把切东西放到该栈上(切都派生于object)然而个object栈意味着Customer对象Integer对象以及假想对象都能被放置到同个栈例子上结果是开发者要子类化数据类型来把数据类型绑定到他们要和的交互东西上去例如在编写定制商业对象时我们就建议定义派生于.Collections.CollectionBase强类型集合原因很简单:基于object定义切被认为是弱类型定义
业界高手们在数十年前就确信强类型优于弱类型所以.NET最终支持强类型这看上去是很自然事情强类型算法当然建议类型化参数-这正是我们在泛型中所用东西
十几年来我们直在使用字母T作为类型化参数名字这样在任何泛型类使用者所提供数据类型地方你都能够找到T使用泛型关键仅仅是提供这个T定义泛型关键在于实现个思路方法或类并且用特定数据类型来替换掉T
C#中泛型支持另外些提炼例如个思路方法或类可以有多个参数化类型并且C#泛型还支持WHERE约束-它用来具体要求类型化参数类型例如如果个泛型类型必须实现接口IDisposable那么C#泛型是支持实现这限制在文章最后我们还要看下约束问题
闲话少说让我们言归正传
2、 使用泛型集合
有些人问我"面向对象编程(OOP)承诺在哪里?"我回答是应该从两个方面来看OOP:你所使用OOP和你创建OOP如果我们简单地看下如果没有如例如Microsoft.NETBorlandVCL以及所有第 3方组件这样OO框架那么很多高级应用几乎就无法创建所以我们可以说OOP已经实现了它承诺不错生产好OOP代码是困难并且可能是极具挫败性;但是记住你不必须定要通过OOP来实现你目标因此下面首先让我们看下泛型使用
当你用Visual Studio或C# Express等快速开发工具创建工程时你会看到对于.Collections.Generic命名空间参考引用在这个命名空间中存在若干泛型数据结构-它们都支持类型化集合散列队列栈字典以及链表等为了使用这些强有力数据结构你所要做仅是提供数据类型
列表1显示出我们定义个强类型集合Customer对象是很容易
列表1 这个控制台应用包含个Customer类和个基于List<T>强类型集合Customers
using ;
using .Collections.Generic;
using .Text;
Generics{
Program{
void Main( args){
List<Customer> customers = List<Customer>;
customers.Add( Customer("Motown-Jobs"));
customers.Add( Customer("Fatman's"));
foreach (Customer c in customers)
Console.WriteLine(c.CustomerName);
Console.ReadLine;
}
}
public Customer{
private customerName = "";
public CustomerName{
get { customerName; }
{ customerName = value; }
}
public Customer( customerName){
this.customerName = customerName;
}
}
}
注意我们有个强类型集合-List<Customer>-对这个集合类本身来说不需要写句代码如果我们想要扩展列表customer我们可以通过从List<Customer>继承而派生个新类
3、 实现个泛型类
种合理实现某种新功能思路方法是在原有事物上进步构建我们已经了解强类型集合并知道种不错用来构建泛型类技术是使用个特定类并删除数据类型也就是说让我们定义个强类型集合CustomerList并且来看下它要把什么东西转化成个泛型类
列表2定义了个类CustomerList后面部分把CustomerList转化成List<T>
列表2定义类CustomerList:
using ;
using .Collections;
using .Text;
Generics{
public CustomerList : CollectionBase{
public CustomerList { }
public Customer this[ index]{
get { (Customer)List[index]; }
{ List[index] = value; }
}
public Add(Customer value)
{ List.Add(value);}
}
}
4、 定义类头
如果我们定义个泛型类我们需要把类头转化成个泛型类所有我们需要做是命名参数并且把类名改成某种泛型List<T>只有个参数T并且我们在以种向后兼容方式工作所以我们知道类名是List列表3显示出列表2中类新类头
列表3 个泛型类头显示出参数化参数T
using ;
using .Collections;
using .Text;
Generics{
public List<T> : CollectionBase {}
5、 实现泛型字段
如果我们需要把任何字段转换成泛型字段我们将只需简单地把它们类型改变成T(或该字段所描述任何参数)泛型List不需要任何字段但是假定存在个私有整型字段叫foo-我们将把它泛型化我们将如下重新定义它:
private T foo;
当参数T被填充到类中时List T也将因foo被填充
6、 定义泛型思路方法
接下来我们为所需要参数化类型定义其它些特性这包括属性思路方法和事件在我们例子中在Customer出现每处我们都用参数T替换它完成后泛型列表类显示于列表4中
列表4 个基于.Collections.CollectionBase轻量级参数化泛型列表类
using ;
using .Collections;
using .Text;
Generics{
public List<T> : CollectionBase {
public List{ }
public T this[ index] {
get { (T)List[index]; }
{ List[index] = value; }
}
public Add(T value) {
List.Add(value);
}
}
}
为了测试该定制列表注释掉使用.Collections.Generic命名空间句并且把列表4中List<T>使用在列表1代码中;它将以同样方式工作
全面地修改.NETList<T>是不必要而且它也包含远比我们举例多得多特性;但是列表4显示出这种机制对于定义定制泛型类是多么容易
7、 增加类型约束
最后要讨论是约束问题约束被应用于类或其它特性上并且使用下面语法:
Where T : constra_type
例如任何我们想要通过using语句所使用如个SqlDataReader必须实现Idisposable接口这是如下方式使用using语句:
using(Form f = Form){...}
就象个try..finally块样工作-总是清除新创建资源其工作原理很简单只需要CLR针对在该using语句中创建对象发出个到IDisposable.Dispose即可例如在上面这句中个新表单被创建并且在using语句退出的前即Form.Dispose
要对个泛型类施加以确保该类实现了接口IDisposable我们将添加先行词where T:Idisposable在列表4中泛型列表上施加约束后我们将重新修改列表4如下面列表5所示
列表5 增加个约束到泛型类以确保我们List<T>中所有值T实现接口Idisposable
using ;
using .Collections;
using .Text;
Generics{
public List<T> : CollectionBase where t : IDisposable{
public List{ }
public T this[ index]{
get { (T)List[index]; }
{ List[index] = value; }
}
public Add(T value){ List.Add(value);}
}
}
先行词where值可以是类接口结构实现个无参公共构造器或有个特定基类类详见有关帮助文档
8、 整理总结
泛型设计是用来减少你重复实现代码次数-只需改变数据类型即可抽象数据结构如队列栈和列表皆是典型数据结构所以存在针对这些东西泛型类完全可以理解你可以从.NET中派生大量值-通过使用现有泛型类如在.Collections.Generic命名空间中那些
可以肯定在段相当长时间里泛型将会象模式和重构等革新样对开发带来越来越大价值而且新数据结构能被转换成可重用如泛型等代码元素
最新评论