从 Visual Basic 6.0 到 Visual Basic.NET 的转换

Microsoft Visual Basic.NET 是 Microsoft Visual Basic© 的后续版本,它是基于 .NET
框架重新设计的,您可以用它来轻松地创建用于 Microsoft Windows© 操作系统和 Web 的下一代应用程序。使用 Visual
Basic.NET,可视化开发 Web 应用程序、Web 服务、Windows 应用程序和服务器端组件将变得轻而易举。此外,Visual Basic.NET
使用了 Windows 应用程序的 XCOPY 部署方案,使您不必再担心 DLL 版本问题。随着 Visual Basic.NET 的发布,“DLL
噩梦”将成为过去。

在设计 Visual Basic.NET 时,我们着眼于世界各地 Visual Basic 开发者的要求。Visual Basic
语言现在是真正的面向对象语言,并支持实现继承。窗体设计器支持可视化继承,并包含窗体自动调整大小、资源本地化和访问选项支持等新特性。现在的数据工具继续支持 XML
数据,并可以共同使用设计时数据绑定和断开数据。此外,Visual Basic.NET 是基于 .NET 框架直接创建的,因此可以使用所有的平台特性,并能够与其他
.NET 语言协同工作。

在发布这些功能的同时,我们对产品的几个方面作了修改。本文档介绍了从 Visual Basic 6.0 到 Visual Basic.NET
的一些变更,并解释了进行这些变更的原因。本文还介绍 Visual Basic.NET
升级向导的功能。它是作为产品的一部分提供的工具,可以帮助您将现有的应用程序升级为 Visual Basic.NET 版本。

有关从 Visual Basic 6.0 升级到 Visual Basic.NET 的其他信息,请参阅白皮书《准备将 Visual
Basic 6.0 应用程序升级到 Visual Basic.NET
》(英文)。此白皮书介绍了升级过程并提供了尽可能顺利升级的建设性意见。

语言

Variant

Visual
Basic 6.0

Variant 是一种特殊的“通用”数据类型,可以包含除定长字符串之外的各类数据。Object
变量用作指向对象的指针。默认的数据类型为 Variant

Visual Basic.NET

公共语言运行时 (CLR) 使用 Object 作为通用数据类型。Visual Basic.NET 没有继续使用
Variant 作为通用数据类型,而是选择采用 CLR
命名规则,以避免在跨语言开发时造成混乱。仅使用一种通用数据类型将简化类型系统。默认的数据类型为 Object

升级
向导

Variant 数据类型变为 Object,因此以下代码:

Dim x As Variant

升级后将变为:

Dim x As Object

Integer 和 Long

Visual
Basic 6.0

Long 变量存储为带有符号的 32 位数字,而 Integer 变量存储为 16 位数字。

Visual Basic.NET

Long 变量存储为带有符号的 64 位数字,Integer 变量存储为 32 位数字,而 Short
变量存储为 16 位数字。在 32 位系统中,32 位整数操作比 16 位和 64 位整数操作都要快。这意味着 Integer
将是最有效和最基本的数字类型。

由于部分 .NET 框架技术以现代的 32 位和 64 位技术为基础,因此根据新技术更新数据大小是明智之举。

升级
向导

修改变量的类型,因此以下代码:

Dim x As Integer
Dim y As Long

升级后将变为:

Dim x As Short
Dim y As Integer

Currency

Visual
Basic 6.0

Visual Basic 6.0 支持 Currency 数据类型。您不能将变量声明为 Decimal
类型(虽然变量可以具有子类型 Decimal)。

Currency 变量以整数格式存储为 64 位数字,以 10,000 为标度,以将数字表示为定点数,其小数点左边为 15 位,右边为 4
位。这种表示形式可以表示 -922,337,203,685,477.5808 至 922,337,203,685,477.5807 范围内的数字。

Decimal 变量存储为带有符号的 96 位整数,标度为 10 的不同乘幂。10 次幂的刻度因子指定了小数点右边的数字位数,其范围为 0
至 28。当指数为 0 时(无小数位数),最大的可能值为 +/-79,228,162,514,264,337,593,543,950,335。当指数为 28
时,最大值为 +/-7.9228162514264337593543950335,最小的非零值为
+/-0.0000000000000000000000000001。

Visual Basic.NET

Currency 数据类型的精度不够,无法避免四舍五入的误差,因此创建了 Decimal
这种数据类型。

升级
向导

Currency 数据类型转换为 Decimal,因此以下代码:

Dim x As Currency

升级后将变为:

Dim x As Decimal

Date

Visual
Basic 6.0

Date 变量在内部以 Double 格式存储,能够作为 Double 类型的变量操作。

Date 变量存储为 IEEE 64 位浮点数,表示从 100 年 1 月 1 日到 9999 年 12 月 31 日的日期和从
0:00:00 到 23:59:59 的时间。任何可识别的文字日期都可以指定为 Date 变量。

当其他数字类型转换为 Date 时,小数点左边的值表示日期信息,而小数点右边的值表示时间信息。午夜为 0,正午为 0.5。整个数值为负表示
1899 年 12 月 30 日之前的日期。

Visual Basic.NET

Date 在内部存储为 64 位整数,因此无法直接作为 Double 进行操作。.NET 框架提供了
ToOADateFromOADate 函数以进行 DoubleDate
之间的转换。将日期表示为整数形式可以简化并加速对日期的操作。

升级
向导

升级工具并非能够检测到所有使用变量将 Date 存储为 Double 的情况,但它一般会在将 Double
指定为 Date 的位置插入适当的 ToOADateFromOADate 方法。例如,以下代码:

Dim dbl As Double  
Dim dat As Date
Dbl = dat

升级后将变为:

Dim dbl As Double  
Dim dat As Date
Dbl = dat.ToOADate

定长字符串

Visual
Basic 6.0

除类模块的 Public 变量之外,其他变量均可以声明为定长字符串。

Visual Basic.NET

CLR 第一版不支持定长字符串。在后续版本中将添加这一支持功能。

升级
向导

在大多数情况下不会出现问题。假设为定长字符串表现方式,则以下代码:

Dim MyFixedLengthString As String * 100

升级后将变为:

Dim MyFixedLengthString As New VB6.FixedLengthString(100)

有关该主题的全面说明,请参阅白皮书《准备将 Visual
Basic 6.0 应用程序升级到 Visual Basic.NET
》(英文)。

Type

Visual
Basic 6.0

Type 语句用于定义由用户定义的数据类型。

Visual Basic.NET

TypeUser-Defined Type
这两个名称会引起混淆,因为类、枚举和接口也是可以由用户定义的类型。TypeUser-Defined Type
是从 QuickBasic 遗留下来的,在 QuickBasic 中用户可以定义的类型只有结构和记录。CLR 使用 Type
这一名称广义地包含所有数据类型。

因此,在 Visual Basic.NET 中 Type 语句将变为 Structure

升级
向导

Type 语句变为 Structure,因此以下代码:

Type MyType  
MyVariable As Integer
End Type

升级后将变为:

Structure MyType  
Dim MyVariable As Short
End Structure

用户定义类型存储

Visual
Basic 6.0

用户定义的数据类型可以包含某种数据类型、数组或先前定义的用户定义类型的一个或多个元素。在 Visual Basic 6.0
中,它们存储在连续的内存块中。

Visual Basic.NET

格式是最有效的。它可能位于一段连续的内存,也可能不。结构可以被标记为封送处理属性,以确保能够作为连续内存块传递到 COM
组件。

升级
向导

在所有需要添加封送处理属性的位置,API 均标记有 TODO 注释。(属性不是自动添加的,只有将结构传递到 API
时才需要它们。)

True

Visual
Basic 6.0

True 的值为 -1。

Visual Basic.NET

True 的值为 1。

鉴于语言的协同操作,需要一种适用于所有语言的一致表示法。

升级
向导

如果将布尔值强制转换为非布尔值,代码将标记有升级警告。例如,以下代码:

Dim MyBoolean As Boolean
Dim MyInteger As Integer
MyInteger = MyBoolean

升级后将变为:

Dim MyBoolean As Boolean
Dim MyInteger As Short
' UPGRADE_WARNING: Boolean MyBoolean is being converted into a numeric
MyInteger = MyBoolean

Empty

Visual
Basic 6.0

变量均初始化为 Empty,当用于数值表达式时,变量将自动转换为零,当用于字符串表达式时,则自动转换为空字符串。

Visual Basic.NET

对象变量均初始化为 Nothing,当用于数值表达式时,变量将自动转换为零,当用于字符串表达式时,将自动转换为空字符串。使用
Nothing 代替特殊的 Empty 值可以降低语言的复杂性,语言协同操作性也更强。

升级向导

 

Null 和 Null 传播

Visual
Basic 6.0

Null 值为 Variant 的子类型,表示变量不包含有效数据。Null
值通过表达式和函数“传播”。如果表达式的任一部分为 Null,则整个表达式为 Null。将 Null
作为参数传递给大多数函数时,这些函数也将返回 Null

Visual Basic.NET

不支持 Null 传播。使用 ADO.NET 对数据进行编程的模型用于在检索字段的值之前先检查字段的值是否为 Null。包含
null 的变量将作为 DBNull 类型的对象封送处理至 CLR。

Visual Basic.NET 处理 Null 时更加直接:字符串函数(例如
Left())总是返回字符串,与您的预期一样。

升级
向导

Null 值和 IsNull 函数标记有升级警告注释。例如,以下代码:

If x Is Null Then MsgBox "Null"

升级后将变为:

' UPGRADE_WARNING: Use of IsNull() detected  
If IsDBNull(x) Then MsgBox "Null"

Def<Type>

Visual
Basic 6.0

DefBoolDefByteDefIntDefLngDefCurDefSngDefDblDefDecDefDateDefStrDefObj
DefVar 语句用于在模块级设置变量、参数和过程返回类型(以指定字符开始)的默认数据类型。

Visual Basic.NET

避免使用隐式类型声明,提高了代码的可读性和可靠性。

升级
向导

将变量类型的显式声明插入代码。例如,以下代码:

DefStr a-z
  
Sub MySub
s = "Hello"
End Sub

升级后将变为:

Sub MySub
    
Dim s As String
s = "Hello"
End Sub

块内的局部变量

Visual
Basic 6.0

从包含声明的行至过程结束的范围内,局部变量均可见。

Visual Basic.NET

Visual Basic.NET 支持变量的块范围。这意味着从包含声明的行开始,至出现声明的块结束,局部变量均可见。例如:

Sub Test(x As Integer)
If x < 0 Then
Dim y As Integer = - x
'...
Else
'...
End If
End Sub

以上示例中的变量 y 仅在声明该变量的块中可用;更确切地说,它仅在其声明至 Else 语句之间可用。如果需要在整个过程中使用变量,则必须在
If/Else/End If 控制结构之外声明该变量。

变量的块范围是许多结构语言共有的功能。过程局部变量允许定义过程内部变量,从而对结构化编程提供支持,与此类似,块级别变量允许定义代码块内部变量,从而对结构化分解提供支持。

升级
向导

如果变量在块内声明,变量将自动移至模块级范围。例如,以下代码:

If x =1 Then
  
Dim y As Integer
End If

升级后将变为:

Dim y As Integer
  
If x =1 Then
End If

新的自动重新实例化

Visual
Basic 6.0

窗体的类变量声明 Dim x As New <classname> 将导致编译器每次引用
x
时生成代码。此代码检查 x 是否为 Nothing;如果是
Nothing,则创建类的新实例。例如,以下代码:

Dim x As New MyClass
  
'...
Call x.MyMethod()

等同于:

Dim x As MyClass
  
'...
If x Is Nothing Then
Set x = New MyClass
End If
Call x.MyMethod()

即使变量已经设置为 Nothing,在下一次调用时该变量仍将重新实例化。

Visual Basic.NET

窗体的变量声明 Dim x As New <classname> 等同于 Dim x As
<classname> = New <classname>
。引用通过此语法声明的变量不会生成特殊代码。

Visual Basic.NET 声明 As New 比 Visual Basic 6.0
中的同一声明更加有效。大多数对这类变量的引用不需要额外的开销。而且,Visual Basic 6.0
的“自动实例化”行为对于发现它的许多编程人员来说非常古怪。

升级
向导

这极少会成为问题。但是,如果代码尝试使用已设置为 Nothing
的类,将导致运行时异常。该异常很容易检测到。然后,可以方便地修改代码以实例化类的新版本,如下例所示:

Dim x As New MyClass
  
x = Nothing
x = New MyClass

对象终结

Visual
Basic 6.0

COM 引用计数机制用于垃圾回收对象实例。如果对象不在循环中,当对象不再使用,引用计数会立即检测到此情况,并且运行终结代码。

Visual Basic.NET

跟踪垃圾回收器从存储在堆栈变量、模块变量和共享变量中的可及引用开始,将对象过一遍。此跟踪进程作为后台任务运行,因此在指向对象的最后一个引用结束和添加新引用之间有一个不定的时间段。

在某些情况下,客户端确实需要能够强制某一对象释放资源。CLR 规定这样的对象应当实现 IDisposable 接口,这就提供了
Dispose 方法。当客户端结束对具有 Dispose 方法的对象的使用时,它可以显式调用 Dispose
方法以释放其资源。例如,包装数据库连接的对象应当公开 Dispose 方法。

跟踪垃圾回收器能够正确释放引用循环中的对象。此外,跟踪垃圾回收器的性能比引用计数要好得多。

升级
向导

在大多数情况下,这一改变不会导致问题。如果您的代码中使用了资源句柄开放(连接或文件句柄),则必须显式关闭此句柄。此问题易于检测并会导致运行时错误。

数组

Visual
Basic 6.0

数组可以由任何整数数字的上下限限定。如果在声明中未指定下限,将使用 Option Base 语句确定默认下限。

Visual Basic.NET

为了与其他语言协同操作,所有数组的下限均必须为零。这样就不再需要 Option Base 语句。

升级
向导

ReDim

Visual
Basic 6.0

Visual Basic 6.0 中的固定大小数组和不定大小数组有所区别。固定大小数组通过 Dim
语句声明,在此语句包括此声明中的数组界限。动态数组在 Dim 语句中声明,不指定界限信息。在使用动态数组之前,需要通过 ReDim
语句重新标注动态数组。在 Visual Basic 6.0 中,ReDim
语句提供了在单个语句中为动态数组声明和分配空间的快捷方法。ReDim 语句是 Visual Basic 6.0
中唯一能够同时声明和初始化变量的语句。

Visual Basic.NET

ReDim 语句仅用于为数组分配或重新分配空间,而不能用于重新分配数组。这是因为 Visual Basic.NET
中的所有数组均是动态的,在 Visual Basic.NET 中 Dim 语句既可用于声明动态数组,又可用于初始化动态数组。

由于所有变量声明均可声明变量并指定变量的初始值,使用 ReDim 同时声明和初始化变量就变得多余和不必要了。只需要 Dim
语句声明变量使语言更加简单、一致性更高。

升级
向导

如果 ReDim() 用于声明数组,在代码中会自动插入相应的声明。但是,最好的方法是您自己先在数组中插入 Dim
语句,因为使用 ReDim 声明数组需要升级工具来推断正确的声明。使用 ReDim
也产生了不便处理的代码,因为数组在两处进行了同一声明。

赋值

Visual
Basic 6.0
赋值形式有两种:Let 赋值(默认)和 Set 赋值。用 Set
语句为 cn 赋值。

Visual Basic.NET

仅有一种赋值形式。x = y 意味着将变量或属性 y 的值赋给变量或属性 x。对象类型变量的值是对对象实例的引用,因此如果 x
y 是引用类型的变量,将执行引用赋值。这种单一形式的赋值减少了语言的复杂性,并使代码可读性更强。

升级向导

删除 SetLet 语句。解析强类型对象的默认属性,并将属性显式添加到代码中。

有关该主题的全面说明,请参阅白皮书《准备将 Visual
Basic 6.0 应用程序升级到 Visual Basic.NET
》(英文)。

And、Or、Xor 和 Not

Visual
Basic 6.0

AndOrXorNot
运算符可以执行逻辑运算或位运算(取决于表达式)。

Visual Basic.NET

AndOrXor 仅适用于布尔型。对于 AndOr
运算符,如果第一个运算数的值足以确定运算符的结果,则运算符将简化计算。新的运算符 BitOrBitAnd
BitXor 均用于位逻辑运算。Bitxxx 运算符不具有简化作用。

升级
向导

如果 And/Or 语句是非布尔型或者包含函数、方法或属性,此语句将升级为使用兼容性函数,与 Visual Basic 6.0
中的表现形式相同。如果 And/Or 语句是布尔型,此语句将升级为使用本地 Visual Basic.Net 语句。

有关该主题的全面说明,请参阅白皮书《准备将 Visual
Basic 6.0 应用程序升级到 Visual Basic.NET
》(英文)。

运算符优先级

Visual
Basic 6.0

逻辑和位的 AndOrXorNot
运算符的优先级高于比较运算符。

Visual Basic.NET

AndOrXorNot 运算符的优先级低于比较运算符,因此 a > b
And a < c
将被认为是 (a > b) And (a < c)。新的
BitAndBitOrBitXor 运算符的优先级高于比较运算符,因此 a BitAnd
&HFFFF <> 0
将被认为是 ((a BitAnd &HFFFF) <>
0)

由于 BitAndBitOrBitNot
运算符可以返回数值结果,因此其优先级高于关系运算符,这样,就允许这三个运算符返回的结果与其他值进行比较。

升级
向导

由升级向导处理。有关该主题的全面说明,请参阅白皮书《准备将 Visual
Basic 6.0 应用程序升级到 Visual Basic.NET
》(英文)。

调用过程

Visual
Basic 6.0

支持两种类型的过程调用:一种使用 Call 语句,要求使用括号括住参数列表;另一种不使用 Call
语句,不能使用括号来括住参数列表。

在 Visual Basic 6.0
中的一种常见情况是,开发者调用的过程不使用关键字,而又在参数列表外使用括号。幸运的是,当有一个以上的参数时,编译器会将其作为语法错误检测出来。但是,当仅有一个参数时,单一参数外的括号会将参数变量传递为
ByVal 而不是 ByRef。这会导致难以找到的小错误。

Visual Basic.NET

在所有情况下参数列表均需要使用括号。

升级向导

为没有使用括号的过程调用插入括号。

静态过程

Visual
Basic 6.0

通过 Static 关键字可以声明过程,此关键字表明在调用之间保留过程的局部变量。

Visual Basic.NET

在过程中不支持 Static 关键字,并且所有的静态局部变量均需通过 Static 语句显式声明。

需要将过程中的所有变量均声明为静态的情况很少。删除此功能简化了语言,并且提高了可读性,因为局部变量总是位于堆栈中,除非已显式声明为
Static

升级
向导

如果过程标记为 Static,则所有的局部变量均变为
Static

参数的 ByVal/ByRef 默认值

Visual
Basic 6.0

参数未指定其默认值为 ByValByRef 时,其默认值为 ByRef

Visual Basic.NET

<参数未指定其默认值为 ByValByRef 时,其默认值为 ByVal

将参数默认值指定为 ByVal 而不指定为
ByRef,可以避免过程错误地修改由调用方传递的变量。这也使得默认的调用规则与赋值一致,以便参数有效地绑定至表达式(通过表达式赋值为正式参数)。

请用户注意避免由 Visual Basic 6.0 升级到 Visual Basic.NET 带来的混乱。如果用户输入的参数声明未显式指定其默认值为
ByValByRef,IDE 将为其自动添加 ByVal 关键字。

升级
向导

为没有指定 ByValByRef 为默认值的参数添加
ByRef

IsMissing 参数和可选参数

Visual
Basic 6.0

没有默认值的可选 Variant 参数将被初始化为特殊的错误代码,此错误代码可以由 IsMissing
函数检测出来。

Visual Basic.NET

在 Visual Basic.NET 中要求所有的可选参数均指定默认值。这样可以减少语言中特殊值的数量,从而简化语言。

升级
向导

IsMissing 函数由 IsNothing
函数代替,并且标记有升级警告注释。

ParamArray 参数

Visual
Basic 6.0

当变量传递给 ParamArray 参数时,可以通过被调用的函数修改。不支持 ByVal ParamArray
元素。

Visual Basic.NET

当变量传递给 ParamArray 参数时,不能通过被调用的函数修改。不支持 ByRef ParamArray
元素。

ParamArray 参数最常见的情况是不修改传递给此参数的变量。不支持 ByRef ParamArray
参数简化了 ParamArray 调用规则,因为 ParamArray
参数将被指定为正常数组。这样,ParamArray 参数可以扩展到任何元素类型,同时需要 ParamArray
参数的函数均可通过数组(而不是参数列表)直接调用。

升级
向导

过程的 ParamArray 参数标记有升级警告。例如,以下代码:

Function MyFunction(ParamArray p() As Variant)
  
'...
End Function

升级后将变为:

' UPGRADE_WARNING: ParamArray p was changed from ByRef to ByVal
  
Function MyFunction(ByVal ParamArray p() As Object)
'...
End Function

声明中的 As Any 参数

Visual
Basic 6.0

本地 API 的参数可以声明为 As Any,这样对本地 API
的调用就可以传递任何数据类型。通过这一方法,可以调用参数支持两种或多种数据类型的 API。

Visual Basic.NET

重载的 Declare 语句可以定义为允许调用带有两种或多种数据类型的本地 API。例如,以下 Declare 语句:

Private Declare Function GetPrivateProfileString _

Lib "kernel32" Alias "GetPrivateProfileStringA" ( _
ByVal lpApplicationName As String, _
ByVal lpKeyName As Any, _
ByVal lpDefault As String, _
ByVal lpReturnedString As String, _
ByVal nSize As Long, _
ByVal lpFileName As String) As Long

可以由两个 Declare 版本代替,一个接受 Long,一个接受字符串。

Overloads Private Declare Function GetPrivateProfileStringKey _

Lib "kernel32" Alias "GetPrivateProfileStringA" ( _
ByVal lpApplicationName As String, _
ByVal lpKeyName As String, _
ByVal lpDefault As String, _
ByVal lpReturnedString As String, _
ByVal nSize As Long, _
ByVal lpFileName As String) As Long
Overloads Private Declare Function GetPrivateProfileStringNullKey _
Lib "kernel32" Alias"GetPrivateProfileStringA" ( _
ByVal lpApplicationName As String, _
ByVal lpKeyName As Long, _
ByVal lpDefault As String, _
ByVal lpReturnedString As String, _
ByVal nSize As Long, _
ByVal lpFileName As String) As Long

这提高了类型的安全性,并减少了导致程序失败的小毛病。这一情况的存在是因为编译器不允许通过没有显式定义的数据类型来调用 API。

升级
向导

使用 As Any 参数的 Declare 语句标记有升级警告。

Implements

Visual
Basic 6.0

Implements 语句指定在其出现的类模块中实现的接口或类。

 

Visual Basic.NET

Visual Basic.NET 中的 Implements 与 Visual Basic 6.0 中的 Implements
有两个本质区别:

  • Implements 语句中不能指定类。
  • 每一种实现方法均要求在方法声明语句的结束处使用 Implements 子句。该子句指定其实现的接口方法。

由于要求每一种实现接口方法的方法均使用 Implements
子句,所以提高了代码的可读性;在阅读使用方法来实现接口方法的的代码时,这一优点显而易见。

升级
向导

如果类 a 实现类 b,则将为类 b 声明接口,且类
a 将变为实现类 b 的接口:

Interface _b
  
Function MyFunction() As String
End Interface
Class a
Implements _b
Function b_MyFunction() As String Implements _b.MyFunction
End Function
End Class

属性

Visual
Basic 6.0

在 Visual Basic 6.0 中,特定属性的 GetLetSet
属性函数可以通过不同级别的访问选项声明。例如,Property Get 函数可以声明为 Public
Property Let 可以声明为 Friend

Visual Basic.NET

属性的 GetSet 函数必须具有相同级别的访问选项。这样就便于 Visual Basic.NET 与其他 .NET
语言协同操作。

升级
向导

如果访问选项的级别不同,则新属性为 Public

默认属性

Visual
Basic 6.0

任何成员均可标记为类的默认值。

Visual Basic.NET

只有接受参数的属性可以标记为默认值。对于将成为集合中的索引的带参数属性,这一情况很常见。

这使得代码的可读性更强,因为对没有成员的对象变量的引用通常指向对象自身,而不是指向上下文中的对象和其他上下文中的默认属性。例如,语句 Call
Display(TextBox1)
可能是将文本框实例传递给 Display 函数,也可能是传递文本框的内容。

此外,删除这种二义性避免了使用单独的语句执行引用赋值。赋值 x = y 总是意味着将变量 y
的内容赋值给变量 x,而不是将 y 引用的对象的默认属性赋值给 x
引用的对象的默认属性。

升级
向导

尽可能解析默认属性。无法解析时(延迟绑定对象)将添加错误注释。

枚举

Visual
Basic 6.0

枚举常数可以无限定地被引用。

Visual Basic.NET

如果在文件或项目级别为枚举添加了 Import,则枚举常数可以无限定引用。

这样可以与类、结构和接口保持一致,在类、结构和接口中,可以给成员赋予通用名称,而不必担心与其他成员冲突。例如,Color 枚举和
Fruit 枚举均可以包含名称为 Orange 的常数。在 Visual Basic 6.0
中的规则是,为枚举常数加上前缀使每个常数保持唯一。这使常数名称非常累赘,如 MsColorOrange 和
MsFruitOrange。

升级
向导

对枚举的引用将变为完全限定。

While

Visual
Basic 6.0

While 语句以 WEnd 语句结束。

Visual Basic.NET

为了与其他块结构保持一致,While 的结束语句变为 End
While
。这提高了语言的一致性和可读性。

升级
向导

WEnd 语句变为 End While

On…GoTo 和 On…GoSub

Visual
Basic 6.0

根据表达式的值,On expression GoTo destinationlist
On expression GoSub destinationlist
语句使程序转向目标列表中的若干个指定行之一。

Visual Basic.NET

On…GoToOn…GoSub 是非结构化的编程构造。它们的使用让程序更加难以阅读和理解。Select
Case
可以提供一种更加结构化和灵活的方法来执行多个分支。

注意:仍然支持 On Error GoTo

升级
向导

以下示例:

On MyVariable GoTo 100,200,300

将标记有升级错误:

' UPGRADE_ISSUE On MyVariable GoTo was not upgraded
  
On MyVariable GoTo 100,200,300

您应当重写代码以避免使用这样的语句,例如:

On x Goto 100,200,300

可以重写为:

Select Case x
  
Case 1: '插入第 100 行的代码
Case 2: '插入第 200 行的代码
Case 3: '插入第 300 行的代码
End Select

GoSub…Return

Visual
Basic 6.0

GoSub lineReturn 语句在过程中分支到子例程,然后从子例程返回。

Visual Basic.NET

GoSub…Return
是非结构化编程构造。它的使用让程序更加难以阅读和理解。一个更加结构化的替代方案是:创建可以调用的独立过程。

升级
向导

On…GoTo 相同,这些语句均标记有升级错误。

LSet

Visual
Basic 6.0

LSet 用空格填充字符串使其为指定长度,或者将用户定义类型的变量复制到另一个用户定义类型的变量。

Visual Basic.NET

不支持 LSet 语句。LSet
对类型而言很不安全,因此会在运行时导致错误。此外,由于它对类型而言不安全,因此执行时代码必须完全可靠。删除 LSet
语句后无法将一个结构复制到另一个结构;但是,可以修改 Visual Basic.NET 代码,使用 RtlCopyMemory
来获得相同的效果。

升级
向导

语句:

LSet a1 = a2

将标记有升级错误

' UPGRADE_ISSUE: LSet cannot assign a UDT from one type to another
  
LSet a1 = a2

VarPtr、StrPtr 和 ObjPtr

Visual
Basic 6.0

VarPtrStrPtrObjPtr 以整数形式返回变量的地址,然后将此地址传递到使用地址的 API
函数(例如 RtlCopyMemory)。VarPtr 返回变量的地址,StrPtr
返回字符串的地址,ObjPtr 返回对象的地址。这些函数均未记录在文档中。

Visual Basic.NET

可以检索数据项的地址,但是检索必须通过调用 CLR 才能进行。这是因为 CLR 通常可以在内存中自由移动项目,因此需要让 CLR
知道何时在使用地址,不能移动项目。以下示例检索对象的地址:

Dim MyGCHandle As GCHandle = GCHandle.Alloc(o,GCHandleType.Pinned)

Dim Address As Integer = CInt(MyGCHandle.AddrOfPinnedObject())
'...
MyGCHandle.Free() '再次允许移动对象实例

允许运行时移动数据项目能够改善运行时的性能。

升级
向导

这些语句不会自动升级,因此将标记有“(statement) is not supported”[(语句)不被支持] 的升级错误。例如,以下代码:

a = VarPtr(b)

升级后将变为:

' UPGRADE_ISSUE: Function VarPtr() is not supported
  
a = VarPtr(b)

这也会导致编译错误。

文件 I/O

Visual
Basic 6.0

语言中包括文件 I/O 语句。

Visual Basic.NET

通过类库使用文件 I/O 操作。从语言中删除文件 I/O 语句以便在 Visual Basic.NET 中使用不同的 I/O 库。如果语言中存在文件
I/O 语句,将会使代码更加累赘,标识符 OpenClosePrintWrite
将成为保留字。

升级
向导

文件 I/O 语句将升级为相应的函数。例如,以下代码:

Open nput )

Debug.Print

Visual
Basic 6.0

Debug.Print 将一行文字输出到“立即”窗口。

Visual Basic.NET

Debug.WriteLine 将一行文字输出到“输出”窗口。还可以使用 Debug.Write
方法将文字输出到“输出”窗口,并且没有换行符。

升级
向导

Debug.Print 升级为 Debug.WriteLine

资源文件

Visual
Basic 6.0

Visual Basic 6.0 支持每个工程使用一个 .res 文件。

Visual Basic.NET

Visual Basic.NET 支持多种资源文件。可以绑定窗体以自动从新的 .resX 格式资源文件中检索资源。任何 CLR 类均可存储在 .resX
文件中。

升级
向导

文件由 .res 升级为 .resX,并且代码被修改以便从 .resX 文件中加载。

Windows 应用程序

Visual Basic 窗体

Visual
Basic 6.0

Visual Basic 6.0 具有自己的窗体包,用于创建图形 Windows 应用程序。

Visual Basic.NET

对于 Visual Basic.NET,Windows 窗体是一种新的窗体包。由于 Windows 窗体是以公共语言运行时 (CLR) 为目标构造的,因此
Windows 窗体可以充分利用 CLR 的全部功能。特别是,由于 Windows
窗体包具有部署、应用程序分离、版本和代码访问安全特性方面的优势,您现在可以构造基于 Windows 的客户端应用程序,其部署和更新明显更加简易。您甚至可以构造与
HTML 具有相同浏览器部署方案的 Windows 窗体应用程序。正如代码访问安全性的粒度控制一样,这些特性也使得在浏览器中使用 Windows
窗体控件非常令人瞩目。

Windows 窗体集还为 Visual Basic
开发者提供了许多新功能,例如可视化继承、改进的本地化和访问支持、自动调整窗体大小和就地菜单编辑器。

升级
向导

将 Visual Basic 窗体升级为 Windows 窗体。

PrintForm 方法

Visual
Basic 6.0

PrintForm 方法将 Form
对象的图象一个字节一个字节地发送至打印机。但是,此打印功能在某些窗体中无法正常工作。

Visual Basic.NET

在 Windows 窗体中,Visual Basic.NET
采用的打印框架使您可以快速生成复杂的打印文档。它还包括内置的“打印预览”对话框。

升级
向导

PrintForm
方法调用标记有升级错误。您可以使用新的打印框架创建打印文档,甚至可以拍下应用程序窗口的屏幕快照并进行打印。

Circle、Cls、PSet、Line 和 Point 方法

Visual
Basic 6.0

通过 CircleClsPSetLinePoint
方法,您可以在窗体中绘图,也可以清除这些图象。

Visual Basic.NET

Windows 窗体具有一套新的图形命令,用于替换 CircleClsPSetLine
Point。Windows 窗体包是在 GDI+ 的基础上构建的。GDI+ 是功能丰富的二维文字和图象处理图形库,现在可以直接在 Visual
Basic.NET 中使用。在以前的版本中,如果不通过 Declare 语句和 GDI API,Visual Basic
程序员无法使用这些功能。虽然这一转变比较大,但是 GDI+ 的灵活性和强大功能让程序员能够快速开发应用程序,而使用以前版本的 Visual Basic
将会花费多得多的工作量。

升级
向导

对这些方法的调用标记有升级错误。您可以在 System.Drawing 中记下使用 GDI+
类的图形调用。

Name 属性

Visual
Basic 6.0

Name 属性返回代码中使用的名称以识别窗体、控件或数据访问对象。在运行时为只读。

Visual Basic.NET

在运行时 Windows 窗体不支持窗体和控件的 Name 属性。如果需要迭代 Controls
集合以查找某一名称的控件,您可以使用 .NET 框架的 System.Reflection 类进行查找。

升级
向导

控件的 Name 属性将标记有升级错误。

Caption 属性

Visual
Basic 6.0

某些控件(例如 Label)具有 Caption 属性,用于确定在控件中或控件旁边显示的文字。其他控件(例如
TextBox)具有 Text 属性,用于确定控件中包含的文字。

Visual Basic.NET

在 Windows 窗体中,对于所有控件,用于显示控件中文字的属性均统一称为 Text。这简化了控件的使用。

升级
向导

将控件的 Caption 属性变为 Text

Tag 属性

Visual
Basic 6.0

Tag 属性可以返回或设置用于存储程序所需额外数据的表达式。

在 Visual Basic 6.0 中无法扩展内置控件,所以 Tag 属性是必需的。

Visual Basic.NET

在 Windows
窗体中,您可以使用继承来扩展内置控件,并添加自己的属性。将继承作为工具使用明显使内置控件更加灵活。您不仅可以根据需要添加任意多种属性,还可以将这些属性设为强属性。

升级
向导

兼容库中的 Windows 窗体扩展程序 Tag 控件用于提供相同的功能。

ScaleMode 属性

Visual
Basic 6.0

ScaleMode 属性返回或设置一个值,以在使用图形方法或定位控件时表明对象的坐标度量单位。

Visual Basic.NET

Windows 窗体始终使用象素作为度量单位,简化了窗体布局。

此外,Windows 窗体使用更好的方法来调整大小。AutoScaleBaseSize 属性根据屏幕的分辨率 (dpi)
和使用的字体大小自动调整缩放比例。

升级
向导

使用“twip”(缇)(Visual Basic 6.0 中 ScaleMode 的默认设置)的代码将完全升级。如果
ScaleMode 为非缇,您将遇到调整大小方面的问题。

有关该主题的全面说明,请参阅白皮书《准备将 Visual
Basic 6.0 应用程序升级到 Visual Basic.NET
》(英文)。

字体

Visual
Basic 6.0

窗体和控件可以使用任何 Windows 字体。

Visual Basic.NET

窗体和控件只能使用 TrueType 或 OpenType
字体。使用这些类型的字体可以解决不同操作系统版本及其本地化版本之间的许多不一致性问题。这些字体还具有不依赖设备分辨率和反走样等功能。

升级
向导

如果在应用程序中使用非 TrueType 字体,这些字体将变为默认的 Windows
窗体字体,但其格式(大小、粗体、斜体和下划线)将会丢失。

Screen.MousePointer 属性

Visual
Basic 6.0

Screen 对象的 MousePointer
属性可以返回或设置一个值,以表明运行时鼠标在应用程序窗体外部显示的鼠标指针类型。

Visual Basic.NET

如果鼠标指针位于应用程序内部的窗体中,则可以进行操作;当其位于应用程序外时则不能。在今后的版本中我们将继续完善其功能。

升级
向导

使用 Sceen.MousePointer 的语句标记有升级错误。

Timer.Interval 属性

Visual
Basic 6.0

Timer 控件的 Interval 属性返回或设置 Timer 事件调用之间的毫秒数。如果设置为 0,则禁用
Timer 控件。Enabled 属性还用于确定计时器是否在运行。这将引起混乱,因为即使 Enabled 属性为
True,如果时间间隔为 0,仍不能启用计时器。

Visual Basic.NET

Interval 属性表明计时器刻度之间的时间(以毫秒为单位)。此属性不能设置为 0。Enabled
属性指定计时器是否在运行。这一方式更加直接,可以简化 Timer 对象的编码。

升级
向导

如果 Timer.Interval 设置为 0,升级向导能够检测到这一情况,并为 Timer.Interval
标记升级错误。

建议您在 Visual Basic 6.0 应用程序中使用
Timer.Enabled,因为此属性可以顺利升级。

控件数组

Visual
Basic 6.0

控件数组是一组共享同一名称和类型的控件。它们也共享同一事件过程。控件数组至少有一个元素,只要您的系统资源和内存允许,它可以有任意多个元素。同一控件数组的元素具有各自的属性设置。

Visual Basic.NET

Windows 窗体体系结构可以处理使用控制数组的多种方案。例如,在 Windows
窗体中可以通过单一事件句柄处理多个控件的多个事件。

升级
向导

兼容库中的“控件数组 Windows 窗体”扩展程序控件提供了这种功能。

Menu 控件

Visual
Basic 6.0

Menu 控件代表菜单树中的各个项目。同一 Menu 控件实例可以同时在主菜单或上下文菜单中使用。

Visual Basic.NET

MenuItem 控件代表菜单树中的各个项目。MenuItem 控件可以添加至 MainMenu 项目或
ContextMenu 项目,但不能同时添加。要在 MainMenu 对象和 ContextMenu
对象中共享菜单,可以在 MenuItem 中使用 CloneMenu 方法创建菜单副本。

升级
向导

使用上下文菜单的代码将标记有升级错误。可以使用 MenuItem.CloneMenu 创建 MainMenu 项目的副本,用作
ContextMenu 项目。

OLE 容器控件

Visual
Basic 6.0

OLE 容器控件使您可以将 OLE 对象添加至窗体。

Visual Basic.NET

Visual Basic.NET 中没有 OLE 容器控件。如果需要与 OLE 容器控件相当的控件,可以将 WebBrowser
控件添加至窗体,并将其用作 OLE 容器控件。

升级
向导

在升级报告中报告此升级错误,并在窗体中放置不受支持控件的占位符。

Image 控件

Visual
Basic 6.0

ImagePictureBox 控件均可显示位图、图标、图元文件、增强型图元文件、JPEG 或 GIF
文件的图形。

Visual Basic.NET

Visual Basic.NET 中的 PictureBox 控件代替了 Visual Basic 6.0 中的
PictureBoxImage 控件。Windows 窗体中的 PictureBox 控件还支持动态 GIF
文件。但是,如果您需要一个简单方案,以便在窗体中绘制图象,您也可以不使用窗体的 OnPaint 事件,而使用 DrawImage
方法。

升级
向导

Image 控件变为 PictureBox 控件。

Line 和 Shape 控件

Visual
Basic 6.0

Line 控件显示水平线、垂直线或对角线。Shape
控件显示矩形、正方形、椭圆形、圆形、圆角矩形或圆角正方形。

Visual Basic.NET

System.Drawing 中的 GDI+ 类代替了 LineShape
控件。要在窗体中绘制各种形状的图形,请不要使用 OnPaint 事件,而使用 GDI+ Draw
方法绘制圆、正方形等各种形状。

升级
向导

水平和垂直 Line 控件变为 Label 控件(没有文字,高度或宽度设置为
1)。对角线控件在升级报告中报告有升级错误,并在窗体中放置不受支持控件的占位符。

矩形和正方形 Shape 控件变为 Label 控件。其他 Shape
控件在升级报告中报告有升级错误,并在窗体中放置不受支持控件的占位符。

Windowless 控件

Visual
Basic 6.0

轻便控件,有时称为无窗口的控件,与常规控件最显著区别是:没有窗口句柄(hWnd 属性)。因此,它们使用的系统资源较少。您可以在设计时将
Windowless 属性设置为 True
以创建轻便用户控件。轻便用户控件只能包含其他轻便用户控件。并非所有容器均支持轻便控件。

Visual Basic.NET

在 Windows
窗体中,大多数无窗口控件默认在窗口中使用。使用无窗口控件的主要优点是:当窗体中有非常大量的控件时,可以减少资源消耗(窗口句柄)。这仅限于 Windows
9x。Microsoft Windows NT? 和 Microsoft Windows 2000 没有这种资源限制。

使用无窗口控件也有缺点(如分层等布局问题),但 Microsoft 认识到了无窗口控件的作用,并将发布示例来展示如何在 Windows
窗体中获得类似效果。

升级
向导

无需特别处理。

Clipboard

Visual
Basic 6.0

Clipboard 对象提供了对系统剪贴板的访问。

Visual Basic.NET

Clipboard 类提供了在系统剪贴板上放置数据和从其上检索数据的方法。新的 Clipboard
类提供了更多功能,并且支持的剪贴板格式比 Visual Basic 6.0 Clipboard
对象更多。对象模块经过了重新构建以支持这些功能。

升级
向导

由于对象模块之间的差异,现有的剪贴板代码无法自动升级。Clipboard
语句将标记有升级错误。

动态数据交换

Visual
Basic 6.0

某些控件具有支持动态数据交换 (DDE) 会话的属性和方法。

Visual Basic.NET

Windows 窗体不支持内置 DDE。

升级
向导

DDE 属性和方法标记有升级警告。

Web 应用程序

WebClass

Visual
Basic 6.0

WebClass 是驻留在 Web 服务器上的 Visual Basic 组件,能够响应浏览器的输入。WebClass 通常包括
WebItems,用于为浏览器和公开事件提供内容。

Visual Basic.NET

Web 窗体具有 .NET 框架功能,可以用来为 Web 应用程序创建基于浏览器的用户界面。Visual Basic.NET
具有“所见即所得”的设计器,可以使用工具箱中的控件创建图形 Web 窗体。这样,Web 用户界面开发与 Windows
开发具有同样的形式。此外,当创建项目后,Internet Information Services (IIS)
服务器不必停止并重新启动即可开始部署新内容,而使用 WebClass 则不能。

升级
向导

WebClass 将升级为 Web 窗体。所有状态存储调用均标记有升级警告。可以重新编写这些代码,以使用 ASP.NET 状态管理的优势。

您也可以选择继续使用 Visual Basic 6.0 中的 WebClass 应用程序,从 Visual Basic.NET Web 窗体中定位至
WebClass 和 WebForm,等等。

ActiveX 文档和 DHTML 应用程序

Visual
Basic 6.0

ActiveX? 文档在 Internet 浏览器窗口中显示,并提供内置的视区滚动、超链接和菜单协商。DHTML 应用程序包含 DHTML 页面和客户端
ActiveX DLL。

Visual Basic.NET

Web 窗体通过采用 HTML 以支持多种应用程序。通过使用寄存在浏览器中的 Windows 窗体控件或已下载的“安全 Windows
窗体”EXE,它能够以更安全的方式支持多种应用程序。此代码在安全沙箱中运行,因此不会对用户的计算机造成损害。

升级
向导

虽然 ActiveX 文档和 DHTML 应用程序无法直接升级,您仍可以在 ActiveX 文档、DHTML 应用程序和 Web
窗体之间切换。

数据

ADO、RDO 和 DAO 代码

Visual
Basic 6.0

ActiveX? 数据对象 (ADO)、远程数据对象 (RDO) 和数据访问对象 (DAO) 用于连接和断开数据访问。

Visual Basic.NET

ADO.NET 提供了断开数据访问的其他类。与用于分布式应用程序的较早版本 ADO 相比,这些类提供了更好的性能和可伸缩性。它们也使 XML
数据与数据库数据的集成更加简单。

升级

Visual Basic.NET 代码中仍然可以使用 ADO、RDO 和 DAO。

ADO、RDO 和 DAO 数据绑定

Visual
Basic 6.0

Visual Basic 窗体中的控件可以绑定到 ActiveX? 数据对象 (ADO)、远程数据对象 (RDO) 和数据访问对象 (DAO)
数据源。

Visual Basic.NET

ADO.NET 为 Windows 窗体控件提供了读/写数据绑定,为 Web 窗体提供了只读数据绑定。

升级
向导

ADO 数据绑定升级为新的 ADO.NET 数据绑定。但是,RDODAO
数据绑定无法升级,将会在升级报告中报告升级错误。

IDE

“立即”窗口

Visual
Basic 6.0

在设计模式的“立即”窗口,您可以运行部分代码,而不必通过其 Startup
对象启动整个应用程序。例如,可以显示窗体、调用模块过程以及与全局变量交互。这是因为 Visual Basic 6.0
是从代码的内存映象运行,而不是调试运行时使用的已创建输出。

Visual Basic.NET

可以从设计模式的“命令”窗口中执行 IDE 命令,但是不能运行应用程序的各个部分。这是因为 Visual Basic.NET
的运行和调试所使用的是运行时的实际输出。这种形式的调试最精确地再现了运行时的行为。

IDE 和项目扩展性

Visual
Basic 6.0

只有 Visual Basic 6.0 支持 Visual Basic 6.0 集成开发环境 (IDE) 扩展模型。

Visual Basic.NET

对于 Visual Studio.NET 中的所有工程类型,新的 IDE
扩展模型是通用的。这使得创建与多种不同类型工程协作的外接程序更加简单。Visual Basic 工程系统扩展模型也可以与 C#
共享,因此工程的特定功能(例如添加引用或更改工程属性)在两种语言中的用法相同。

Visual Studio.NET 代码模型也给扩展级编写者提供了公共对象模型,以编写跨不同语言工程使用的代码。Visual Basic
支持通过代码模型读取代码。要编写代码,您可以从模型中取出一个插入点,然后写入 Visual Basic
语法。