泛型(Generics)是Visual Basic
2005中的一种新特性,然而很多开发者在第一次看到它的时候可能忽略它,但是他们最终会发现,在了解泛型之后,离开了泛型就几乎不能工作了。泛型这个专业术语并没有道出这种特性能够实现的真实功能。假设我们需要编写一个执行数学计算的类(class)。使用标准的代码编写技术,你必须为整型和实数型(对于所有的形式)编写独立的方法。通过使用泛型,你可以一次性编写方法,并让.NET框架组件为你处理数据类型的问题。泛型可以使你在编程过程中体会到更多的快乐。你不需要额外的工作就能体会到代码重用(reuse)的优点。

  阅读导航:

   一、泛型的优点
   使用泛型可以提高性能,其中显著的一个改进是.NET框架组件不会在值类型上使用装箱(boxing);使用泛型类的另一个令人惊讶的特性是IntelliSense居然可以跟踪强数据类型定义。
  
   二、建立泛型类
   使用泛型的时候,你应该选择建立有广泛用途的类,这样的话所建立的泛型类所花费的时间最终会整个开发时间上获得回报。例如,集合就是一种处理多个数据类型的类,而一般你会在多个应用程序中使用同一个集合的多种不同的形式,如果采用泛型,那么就不需要多次重复的建立不同形式的同一集合。

   三、使用泛型类
   我们在上面建立的泛型类在使用方法上与其他类没有什么不同,仍然需要将其实例化。

   四、约束泛型类
   也许你对实例中泛型类能够接受任何数据类型感恐惧,你不得不担心在使用中出现程序仍然会对错误参数产生反映,对,是存在这样的风险,不过我们可以对泛型类加以约束。

   五、为泛型类定义多个类型
   你不必仅仅使用一种数据类型定义每个类,泛型类也提供多个数据类型,你所需要做的是用逗号分开每种数据类型。

   结束语

   尽管泛型类起先看起来仅仅是前进的一步,但是它们实际上是.NET革命中的一个巨大飞跃。使用泛型把你从为每个数据类型建立新类中释放了出来,提高了性能,并减少了开发和调试的时间。为了体会Visual
Studio 2005中最好的部分,你真的应该试着使用这个新特性——你会发现自己将很喜欢它的。

 
泛型有哪些重要优点

  你可能想知道泛型除了减少输入之外还提供哪些功能,毕竟你仍然需要建立类来处理信息。它的最好的特性在于正确地构建的泛型类可以真正减少代码中的安全性问题。由于你使用几个数据类型定义类,你不必依赖于通用Object类型。泛型类依赖于强数据类型定义,这与其它类在处理特定数据类型的时候是相同的。简短的说,尽管你获得了很大的灵活性,但是作为结果的代码却更加优良。

  使用泛型类还可以提高性能。其中最大的一个改进是.NET框架组件不会在值类型上使用包装(boxing)。尽管泛型类可以使用多个数据类型工作,但是它在后台单独地处理每一种数据类型。这种技术确保了在你的工作量最小的情况下,应用程序提供最佳的性能。

  使用泛型类的另一个令人惊讶的特性是IntelliSense居然可以为你跟踪强数据类型定义。与使用对象建立处理多个数据类型的通用方法不同,你的代码依赖于强数据类型定义,这意味着IntelliSense为你提供了更多的信息。这种特性不但使我们更容易处理代码,还减少了错误和调试时间。

  建立泛型类

  使用泛型的时候,你应该选择有广泛用途的类,这样的话建立泛型类所需要的时间最终会在减少开发时间方面给予你回报。例如,集合就是一种处理多个数据类型的类,并且一般你会在多个应用程序中使用同一个集合的多种不同的形式。你不需要每次根据草稿建立集合,而是使用泛型建立一个泛型类原型(prototype)。首先,你需要给代码添加如下所示的Imports语句:

Imports
System.Collections.Generic

  添加Imports语句之后,你就可以建立泛型类了。基本的类看起来很常见。你可以使用属性、函数、子程序、字段或可以在类中使用的其它任何东西,如列表1所示:

  列表1.定义一个泛型类类型

Public Class MyGenericCollection(Of ItemType)

 ’
定义一个通用的集合
 Private Items As Collection(Of ItemType)

 ’
建立构造函数
 Public Sub New()
  Items = New Collection(Of
ItemType)
 End Sub

 ’ 返回集合中数据项的数量
 Public ReadOnly Property
Count() As Integer
  Get
   Return Items.Count
  End Get
 End
Property

 ’ 得到或设置一个特定的数据项
 Default Public Property Item(ByVal
Index As Integer) As ItemType
  Get
   Return Items(Index)
  End
Get
  Set(ByVal value As ItemType)
   Items(Index) = value
  End
Set
 End Property

 ’ 给集合添加新的数据项
 Public Sub Add(ByVal Value
As ItemType)
  Items.Add(Value)
 End Sub

 ’
从集合中删除数据项
 Public Sub RemoveAt(ByVal Item As
Int32)
  Items.RemoveAt(Item)
 End Sub

End
Class

  这个类的声明看起来很常见,但是请留意“(Of
ItemType)”条目。这个条目就是泛型类与标准类的差别。你可以把它看作是一个占位符,在未来实例化这个类的时候,你需要提供类型。当.NET框架组件发现这个条目的时候,它用使用这个类的代码所提供的类型来替换这个条目。当然,你没有必要在类中使用ItemType(数据项类型)——你可以把泛型类随便叫什么名字,就像为变量命名一样。

  由于这是一个集合类,代码首先执行的事务是建立一个保持集合的全局变量。但是,由于你希望把这个集合与泛型数据类型关联起来,因此再次使用专用的“(Of
ItemType)”条目告诉.NET框架组件来建立一个特定的集合。这就是强数据类型定义开始起作用的地方。尽管你并不知道集合将使用的数据类型,但是.NET框架组件将会,而且能够为你建立这种数据类型的集合。

  在所有的类中你都必须包含一个构造函数或者New()子程序。在例子中构造函数实例化集合。同样,一定要使用“(Of
ItemType)”代码来确保代码正确地对待泛型数据。

  你可以像平时一样使用这个集合。例如,Count属性返回集合中数据项的数量。实际上,这段代码与标准类中使用的代码看起来没有差别。

  有时你必须处理特定的数据项类型。Item属性演示了这种原理。请注意,这个属性返回一个ItemType类型的值——你现在并不知道数据的类型,但是未来.NET框架组件会指定类型。实际上,当我建立这个类的时候,IDE自动地为我建立了正确的Set()方法。请注意,这个方法也依赖于ItemType。但是,使用泛型并没有阻止你建立标准的属性条目。例如,property属性是这个类的默认值,因为我们使用Default关键字定义了它。

  这个类的末尾是两个子程序。第一个根据ItemType给集合添加新值;第二个使用数据项编号从集合中删除一个值。开发者不可能把错误的数据类型添加到集合中,因为.NET框架组件指定并监视着数据类型。因此,你不用担心某个人提供了类型错误的数据,尽管这个类接受了通常的输入。我们把这种功能与使用Object进行对比,使用Object时开发者可能提供任何类型的输入信息,而你必须执行检测以确保它是正确的类型。

使用泛型类

  使用上面的代码中的泛型类与使用任何其它的类只有稍微的差别。你仍然需要实例化这个类,并且你也可以使用方法、属性和事件,与使用其它类相似。列表2显示了使用列表1中定义的泛型类的典型示例:

  列表2.使用泛型类

Private Sub btnTest_Click(ByVal sender As System.Object, _
ByVal e
As System.EventArgs) _
Handles btnTest.Click

 ’ 建立新集合
 Dim
CollectInt As New MyGenericCollection(Of String)

 ’
在集合上执行某些事务
 CollectInt.Add(“One”)
 CollectInt.Add(“Two”)
 CollectInt.Add(“Three”)
 CollectInt.RemoveAt(1)

 ’
显示一些统计信息
 MessageBox.Show(“Number of Entries: ” +
CollectInt.Count.ToString())
 MessageBox.Show(“Value of First Item: ” +
CollectInt(0))
End
Sub

  btnTest_Click()方法从建立一个新集合开始。请注意实例化CollectInt对象的代码。与正常的方法不同,它需要开发者提供集合的数据类型。在示例中“(Of
String)”条目指定这个集合将接收String(字符串)类型的值。

  CollectInt被实例化了之后,代码使用CollectInt的方法向集合添加值,并从集合中删除值。这与操作标准的类没有任何区别,因此通常你在操作基于泛型类的对象的时候,不必改变任何技术。

  在使用几个方法操作了第一个数据项(Two)之后,代码以显示集合中数据项的数量和第一个数据项结束。同样,在使用这个对象的时候你不需要做任何专门的工作。Count属性与你预想的工作方式相同。当你处理默认属性Item的时候,你会发现没有必要执行向String类型的转换(conversion)。其原因在于IDE和.NET框架组件都知道你建立的集合使用了String数据类型。此外,IntelliSense也知道它是String数据类型的,如图1所示。请注意,你接受的是特定的String类型的信息,而不是使用Object时接收的通用类型。


图1.使用泛型意味着从IntelliSense中得到特定数据类型的反馈

  约束泛型类

  当你看列表1的时候,你可能开始对泛型类有如此的作用感到惊讶,因为示例类可以接受任何的数据类型。幸运的是,你可以约束泛型类,使它仅仅接受一种特定的数据类型。例如,你可以建立如下所示的一个Address数据类型类:

Public Class Address
 Public Name As String
 Public Address1 As
String
 Public Address2 As String
 Public City As String
 Public
State As String
 Public ZIP As String
End
Class

  你可以通过修改声明来约束泛型类,使它只能接受Address数据类型。例如,你可能希望改变列表1中的集合,如下所示:

Public Class MyGenericCollection(Of ItemType As
Address)

  这个泛型类现在只能接受Address数据类型。任何其它的用法都会产生错误(IDE拒绝编译代码)。你可以把任何通用类型(包括接口)作为约束。例如,你可能希望定义一个泛型类,它只能接受实现IcustomFormatter接口的数据类型。

  为泛型类定义多个类型

  你不必仅仅使用一种数据类型定义每个类。幸运的是,泛型类也提供多个数据类型。你所需要做的是用逗号分开每种数据类型,如下所示:

Public Class MyGenericCollection(Of ItemType1, ItemType2,
ItemType3)

  这个声明接受三个输入的数据类型(不能多,也不能少)。在例子中,代码在数据类型上没有做任何约束,但是你可以轻易地根据需要添加约束。实际上,你可以在同一个声明中带有和不带约束、混合和匹配数据类型,带有约束的数据类型不必拥有相同的约束类型。你可以包含一个使用特定类和另一个依赖于某种接口的数据类型。

  总结

  尽管泛型类起先看起来仅仅是前进的一步,但是它们实际上是.NET革命中的一个巨大飞跃。使用泛型把你从为每个数据类型建立新类中释放了出来,提高了性能,并减少了开发和调试的时间。为了体会Visual
Studio 2005中最好的部分,你真的应该试着使用这个新特性——你会发现自己将很喜欢它的。