Viusal Basic程序员的.NET泛型编程

简介:
一、引言

  在《The  C++  Programming Language》一书中,Bjarne Stroustrop讨论了模板方法在C语言中的伪实现-通过使用预处理和宏来模拟。Stroustrop创建了这种灵活运用C语言的模板和宏的能力,它 使得模板成为用C语言创建类(现在的C++)的相当成熟的一部分。另外的优点是,模板是由编译器进行类型检查的,而不是简单地通过预处理器进行文本替换。

   .net  2.0支持称为泛型的模板。其基本概念是相同的:用一个或多个方法来定义一个方法或类,并指定数据类型作为一个可替代的元素。习惯情况下,都使用大写字符 T。最后,当你使用该方法或类时,指明一种类型给泛型T,然后编译器将基于那种类型使用新的信息来生成一个新的且唯一的方法或类。这种新的元素变成了一个 完整的独特的代码块,这完全得益于编译器的处理能力。

  本文将分析随着.NET 2.0一起发布的泛型方法和类的定义以及泛型类的使用问题。

   二、定义泛型方法

   .NET 2.0的泛型化能力可以定义到单一方法这样的粒度。解决的方法是把数据类型与算法独立开来并参数化该数据类型。每一次用不同的数据类型对该方法的参照引用 都产生一个不同的方法。泛型方法还支持约束和重载。一个泛型方法约束是一个新出现的语言特征,它可以把一个类型约束添加到泛型类型上去;这样以来就限制了 泛型参数的数据类型。因而,可以根据泛型参数的存在情况,对方法进行重载。(接下来的几个例子将分析重载的泛型和非泛型方法。)

  泛型 的典型用法是把数据类型与通用算法分离开来,一个正规的例子就是把排序算法转化成泛型排序算法。一个非常直接的例子是参数化一个Swap方法。列表1向你 展示怎样定义一个泛型Swap方法-该方法交换两种任何类型的参数。它包含一个表明怎样调用泛型方法的控制台应用程序:

  列表1:怎样调用泛型方法

Module Module1
Sub Main()
Dim I As Integer = 5
Dim J As Integer = 7
Swap(Of Integer)(I, J)
Console.WriteLine("I = " & I)
Console.WriteLine("J = " & J)
Dim S As String = "Paul"
Dim R As String = "Lori"
Swap(Of String)(S, R)
Console.WriteLine("S = " & S)
Console.WriteLine("R = " & R)
Console.ReadLine()
End Sub

Public Sub Swap(Of T)(ByRef a As T, ByRef b As T)
Dim temp As T
temp = a
a = b
b = temp
End Sub
End Module

  注意:在这个例子中,你也能把一个对象数据类型使用于该Swap方法,因为所有的.NET类型共享一个通用的类型。

  需要定义一个泛型方法的新的元素有圆括号,Of关键字以及一个描述泛型类型的参数,在方法名Swap的后面的字符(Of T)正是如此。之后,每当使用该泛型类型,都要使用参数化参数(在本例中是T)。

  Swap是一个泛型方法,它有两个可替换的参数和一个可替换的局部变量。例如,Swap(Of Integer)有效地实现了一个有两个整数参数和一个定义为整数的临时变量的Swap方法。

  1. 添加一个泛型方法约束

  假定你想约束列表1中Swap方法中的类型成为非null的结构类型。你可以添加一个约束到Swap上去以指明Swap只可用于值类型(结构)。列表2显示的Swap方法被约束到结构(或值类型)上。最终结果,在列表1中的Swap(Of String)无法运行:

  列表2:带有约束的Swap方法把Swap方法限制到值类型:

Public Sub Swap(Of T As Structure)(ByRef a As T, ByRef b As T)
Dim temp As T
temp = a
a = b
b = temp
End Sub

  参数化类型可以被限制到结构、类、基类、接口以及有缺省构造器(如没有参数的Sub New)的类型。列表2中的加粗的As谓词展示了怎样约束参数化的类型。

  泛型支持定义多个参数化类型,而每个参数化类型可以没有或者有多个约束。

  2. 重载泛型方法

  你可以基于一些参数对方法进行重载,但是没有返回类型,而且方法也能够被通过参数化类型所重载。例如,下面所有这些形式都可以存在于同一个范围之内:

Sub Foo
Sub Foo(ByVal s As String)
Sub Foo(Of T)( ByVal arg As T)
Sub Foo(Of T, U)(ByVal arg1 As T, ByVal arg2 as U)
   三、定义一个泛型类

  泛型类与普通类一样定义在相同的实例中,只有一个区别。当你有一些数据和多 于一个方法并且其间有关密切的关系时,你可以定义一个普通类。当方法和数据工作在一个密切的单元中并且该数据可以被进一步抽象,以至相同的代码可以支持许 多数据类型时,你最好定义一个泛型类。例如,队列、列表和堆栈并不在乎它们存储的东西,而仅在乎怎样存储这些东西。如果你使用一个其中存储有对象的队列、 堆栈或列表,那么你不得不在你的代码的很多地方进行繁琐的类型转化。如果你使用一个泛型队列、堆栈或列表,那么类型转化只是发生在该类内部。这就是说,繁 琐的类型转化场所集中于该类的一个内部点上,而该类的用户可以依赖编译器来进行类型检查,并不要求用户执行if条件检查和类型变换。

   定义一个泛型类就象定义多个泛型方法,只是多了一点:(Of T)构造也可以用于类的头部。为了说明问题,假定你已定义了一个派生于System.Collections.CollectionBase的泛型的强类 型集合(见列表3)。那么现在,你可以把这个类使用于任何数据类型,就好象你已针对所有类型定义了一个定制的类型化的集合:

  列表3:一个泛型的强类型集合

Module Module1
Sub Main()
Dim BrokenBones As TypedCollection(Of OrthoInjury) = New TypedCollection(Of OrthoInjury)
BrokenBones.Add(New OrthoInjury(True,"Broken Right Clavicle", "Vicodin; Heals n 8 to 12 weeks"))
BrokenBones.Add(New OrthoInjury(True, "Fractured Posterior Rib #5", "Heals in 6 to 8 weeks"))
BrokenBones.Add(New OrthoInjury(True, "Fractured Posterior Rib #1", "Heals in 6 to 8 weeks"))
Dim injury As OrthoInjury
For Each injury In BrokenBones
Console.WriteLine("Description: " & injury.Description)
Next
Console.ReadLine()
End Sub
End Module
Public Class TypedCollection(Of T)
Inherits System.Collections.CollectionBase
Default Public Property Item(ByVal Index As Integer) As T
Get
Return CType(List(Index), T)
End Get
Set(ByVal value As T)
List(Index) = value
End Set
End Property
Public Function Add(ByVal value As T) As Integer
Return List.Add(value)
End Function
End Class
Public Class OrthoInjury
Private FHasXray As Boolean
Private FDescription As String
Private FPrognosis As String

Public Sub New(ByVal HasXray As Boolean, ByVal Description As String, ByVal Prognosis As String)
FHasXray = HasXray
FDescription = Description
FPrognosis = Prognosis
End Sub
Public Property HasXray() As Boolean
Get
Return FHasXray
End Get
Set(ByVal value As Boolean)
FHasXray = value
End Set
End Property
Public Property Description() As String
Get
Return FDescription
End Get
Set(ByVal value As String)
FDescription = value
End Set
End Property
Public Property Prognosis() As String
Get
Return FPrognosis
End Get
Set(ByVal value As String)
FPrognosis = value
End Set
End Property
End Class

  如果你读过以前关于类型化的集合的文章,那么你会看到类型化的集合泛型(列表3中的粗体部分)基本上是一种数据类型被参数化的强类型的集合。

   四、使用预定义的泛型类

   幸好,你不需要从头开始定义泛型类。System.Collections.Generics命名空间已定义好了许多典型的数据结构用作泛型,例如 List,Queue和Stack。你仅需要简单地导入该命名空间并声明一个你需要的类型的实例即可。例如,下列代码充分地实现用 .net  2.0泛型List类型化的集合来替换你的定制的类型化的集合:

Dim BrokenBones As System.Collections.Generic.List(Of OrthoInjury) = _
New System.Collections.Generic.List(Of OrthoInjury)

   作为一个一般规则,如果你想要存储多于一个类型(异类类型),可以使用更旧的风格类,如Queue和Stack。如果你只想使用一种类型(同类类型), 可以使用在System.Collections.Generic命名空间中的新的泛型类。通常情况下,你应使用新的泛型类。

   五、选择所学

  能够把传统的复杂的如 C++ 这样的语言与传统的简单的如 VB 这 样的语言隔离开来的东西越来越少了。乍看起来,这种事实有点令人心灰意冷,因为这就意味着如今的VB越发难学了-就象C++一样。不过事实上,任何一种语 言(包括VB)的核心往往是非常相似的;而即使象C++这样的语言,你也总可以选择学习如泛型这样更高级的概念,如果你需要它们的话。总之,你可以选择任 何你想学的东西。

  还应记住,你总是可以选择学习任何编程相关的高级概念-开始作为一个使用者-使用其中的内容,例如泛型List;然后作为一个创建者,学习怎样创建你自己的东西。总而言之,想短时间内学精每一件技术可能无法实现,而且也完全没有必要。














本文转自朱先忠老师51CTO博客,原文链接: http://blog.51cto.com/zhuxianzhong/59806,如需转载请自行联系原作者


相关文章
|
5月前
|
存储 JSON 开发工具
Visual Studio编程效率提升技巧集(提高.NET编程效率)
Visual Studio编程效率提升技巧集(提高.NET编程效率)
Visual Studio编程效率提升技巧集(提高.NET编程效率)
|
7月前
|
存储 安全 编译器
|
2月前
|
传感器 数据采集 物联网
探索.NET nanoFramework:为嵌入式设备编程的新途径
探索.NET nanoFramework:为嵌入式设备编程的新途
63 7
|
7月前
|
开发框架 缓存 前端开发
利用Visual Basic构建高效的ASP.NET Web应用
【4月更文挑战第27天】本文探讨使用Visual Basic与ASP.NET创建高效Web应用的策略,包括了解两者基础、项目规划、MVC架构、数据访问与缓存、代码优化、异步编程、安全性、测试及部署维护。通过这些步骤,开发者能构建出快速、可靠且安全的Web应用,适应不断进步的技术环境。
109 0
|
4月前
|
大数据 开发工具 开发者
从零到英雄:.NET核心技术带你踏上编程之旅,构建首个应用,开启你的数字世界探险!
【8月更文挑战第28天】本文带领读者从零开始,使用强大的.NET平台搭建首个控制台应用。无论你是新手还是希望扩展技能的开发者,都能通过本文逐步掌握.NET的核心技术。从环境搭建到创建项目,再到编写和运行代码,详细步骤助你轻松上手。通过计算两数之和的小项目,你不仅能快速入门,还能为未来开发更复杂的应用奠定基础。希望本文为你的.NET学习之旅开启新篇章!
44 1
|
4月前
|
存储 C#
揭秘C#.Net编程秘宝:结构体类型Struct,让你的数据结构秒变高效战斗机,编程界的新星就是你!
【8月更文挑战第4天】在C#编程中,结构体(`struct`)是一种整合多种数据类型的复合数据类型。与类不同,结构体是值类型,意味着数据被直接复制而非引用。这使其适合表示小型、固定的数据结构如点坐标。结构体默认私有成员且不可变,除非明确指定。通过`struct`关键字定义,可以包含字段、构造函数及方法。例如,定义一个表示二维点的结构体,并实现计算距离原点的方法。使用时如同普通类型,可通过实例化并调用其成员。设计时推荐保持结构体不可变以避免副作用,并注意装箱拆箱可能导致的性能影响。掌握结构体有助于构建高效的应用程序。
142 7
|
4月前
|
Java Spring 自然语言处理
Spring 框架里竟藏着神秘魔法?国际化与本地化的奇妙之旅等你来揭开谜底!
【8月更文挑战第31天】在软件开发中,国际化(I18N)与本地化(L10N)对于满足不同地区用户需求至关重要。Spring框架提供了强大支持,利用资源文件和`MessageSource`实现多语言文本管理。通过配置日期格式和货币符号,进一步完善本地化功能。合理应用这些特性,可显著提升应用的多地区适应性和用户体验。
50 0
|
4月前
|
传感器 数据采集 物联网
探索未来:.NET nanoFramework引领嵌入式设备编程革新之旅
【8月更文挑战第28天】.NET nanoFramework 是一款专为资源受限的嵌入式设备设计的轻量级、高性能框架,基于 .NET Core,采用 C# 进行开发,简化了传统底层硬件操作的复杂性,极大提升了开发效率。开发者可通过 Visual Studio 或 Visual Studio Code 快速搭建环境并创建项目,利用丰富的库和驱动程序轻松实现从基础 LED 控制到网络通信等多种功能,显著降低了嵌入式开发的门槛。
90 0
|
6月前
|
安全 程序员 Shell
老程序员分享:NSIS自定义界面,下载并安装Net.Framework4.8
老程序员分享:NSIS自定义界面,下载并安装Net.Framework4.8
|
7月前
|
JSON 编解码 Go
Golang深入浅出之-HTTP客户端编程:使用net/http包发起请求
【4月更文挑战第25天】Go语言`net/http`包提供HTTP客户端和服务器功能,简化高性能网络应用开发。本文探讨如何发起HTTP请求,常见问题及解决策略。示例展示GET和POST请求的实现。注意响应体关闭、错误处理、内容类型设置、超时管理和并发控制。最佳实践包括重用`http.Client`,使用`context.Context`,处理JSON以及记录错误日志。通过实践这些技巧,提升HTTP编程技能。
86 1