×

[转]全面剖析VB.NET技术(完整篇)

Kalet Kalet 发表于2009-03-20 12:00:14 浏览187 评论0

抢沙发发表评论

Visual Basic.Net中有三种访问文件系统的方法:第一种是使用 Visual Basic 运行时函数进行文件访问 (VB传统方式直接文件访问);第二种是通过.Net中的System.IO模型访问;第三种是通过文件系统对象模型FSO访问。

文件是存储在某种介质上数据的集合,就其本身来讲,文件只不过是磁盘上的一系列相关的数据字节。当应用程序访问文件时,它必须假定字节是否表示字符、数据记录、整数、字符串等。通过指定文件的访问类型来告诉应用程序假定什么内容。[转]全面剖析VB.NET技术(完整篇)

Visual Basic 提供三种类型的文件访问:

1.顺序,用于在连续的块中读取和写入文本文件。

2.随机,用于读取和写入结构为固定长度记录的文本或二进制文件。

3.二进制,用于读取和写入任意结构的文件。



使用 Visual Basic 运行时函数进行文件访问



VB.Net保留了VB早期的直接文件访问的方式即通过一些相关的函数直接访问操作文件。 下表分别列出了三种直接文件访问类型的所有可用文件访问函数。

函数
顺序
随机
二进制
说明

FileOpen 函数
X
X
X
打开输入或输出文件

FileClose 函数
X
X
X
关闭对用 FileOpen 函数打开的文件

Input 函数
X

X
从打开的顺序文件中读取数据并将数据分配给变量。

InputString 函数
X


返回 String 值

LineInput 函数
X


从打开的顺序文件中读取一行数据并将它赋给 String 变量。

Print、Printline 函数
X


将格式化的显示数据写入顺序文件。

Write、WriteLine 函数
X


将数据写入顺序文件。



要对文件进行操作,首先要打开文件,使用FileOpen函数。

示例:以 Output 模式共享方式打开C盘下的readme.txt文件。

FileOpen(1, "c:\readme.txt", OpenMode.Output, OpenShare.Shared)

当操作文件结束后,需要关闭文件防止文件内容的丢失,此外需要重新打开文件时也需要关闭文件,用FileClose函数,关闭刚才打开的文件c:\readme.txt:

FileClose(1);

当以input模式打开顺序文件时,要打开的文件必须已经存在,否则打开出错,以Output或Append模式打开一个不存在的文件时,FileOpen先创建该文件,然后打开。

其他的一些函数:

Dir 函数:返回表示匹配指定模式或文件属性的文件名、目录名或文件夹名的字符串或返回驱动器卷标的字符串。

EOF 函数:当到达以 Random 或顺序 Input 模式打开的文件尾时,返回 Boolean 值 True。

FileCopy 函数:复制文件

FileDateTime 函数:返回指示创建或最后修改文件的日期和时间的 Date 值。



FileLen 函数:返回以字节表示的指定文件长度的 Long 值。

FreeFile 函数:返回一个 Integer 值,表示可由 FileOpen 函数使用的下一个文件号。

GetAttr 函数:返回表示文件、目录或文件夹的属性的 FileAttribute 值。

Loc 函数:返回一个 Long 值,该值指定打开文件中当前的读/写位置。

LOF 函数:返回一个 Long 值,表示用 FileOpen 函数打开的文件的大小(以字节为单位)。

Seek 函数:返回一个 Long 值,指定用 FileOpen 函数打开的文件中的当前读/写位置,或设置用 FileOpen 函数打开的文件中的下一个读/写操作的位置。

SetAttr 函数:设置文件属性信息。

1、顺序文件的操作

从文件中读取字符串

有三个函数可以从顺序文件中读取字符串:Input,InputString和LineInput。

Input函数

从打开的顺序文件中读取数据并将数据分配给变量。

Public Sub Input( FileNumber As Integer, ByRef Value As Object)

其中参数FileNumber为有效文件号;Value为被赋予从文件读取的值的变量,它不能为数组或对象变量。

下面的例子是一个写入和读取文本example.txt的Hello,world!例子,新建一个控制台应用程序,写入下面的代码查看结果。

FileOpen(1, "c:\example.txt", OpenMode.Output)

Write(1, "Hello,")

Write(1, "World!")

FileClose(1)



Dim s As String

FileOpen(1, "c:\example.txt", OpenMode.Input)

Do While Not EOF(1)

Input(1, s)

Console.WriteLine(s)

Loop

FileClose(1)

InputString函数

返回 String 值,该值包含以 Input 或 Binary 模式打开的文件中的字符。

InputString ( ByVal FileNumber As Integer, ByVal CharCount As Integer ) As String

其中参数FileNumber是有效文件号,CharCount是指定要读取的字符个数的有效数值表达式。

与 Input 函数不同,InputString 函数返回它读取的所有字符,包括逗号、回车符、换行符、引号和前导空格等。对于以 Binary 访问模式打开的文件,如果试图在 EOF 返回 True 之前用InputString 函数读取整个文件,则会产生错误。在用 InputString 读取二进制文件时,用 LOF 和 Loc 函数代替 EOF 函数,而在使用 EOF 函数时则使用 FileGet 函数。

示例:

Dim s As String

FileOpen(1, " c:\example.txt ", OpenMode.Binary)

Do While Not EOF(1)

s = InputString(1, 9)

Console.WriteLine(s)

Loop

FileClose(1)

LineInput 函数:

从打开的顺序文件中读取一行数据并将它赋给 String 变量。

Public Function LineInput (ByVal FileNumber As Integer) As String

参数 FileNumber 是有效文件号。

此函数从文件一次读取一个字符,直到遇到回车符(Chr(13))或回车–换行符(Chr(13) + Chr(10))为止。回车–换行序列被跳过而不是附加到字符字符串上。

示例:

Dim s As String

FileOpen(1, " c:\example.txt ", OpenMode.Binary)

Do While Not EOF(1)

s = LineInput(1)

Console.WriteLine(s)

Loop

FileClose(1)



把字符串写入文件

如果要向文件中写入数据,可以用Print/PrintLine函数,如果要写入的数据是字符串或是数值,则可以用Write/WriteLine函数,要写文件,应该先将文件以Output或Append方式打开,然后菜可以使用Print函数或Write函数。

Print/PrintLine函数:将格式化的显示数据写入顺序文件。

Public Sub Print( ByVal FileNumber As Integer, ByVal ParamArray Output() As Object)

Public Sub PrintLine( ByVal FileNumber As Integer, Val ParamArray Output() As Object )

其中参数FileNumber 是有效文件号,Output 是要写入文件的零个或更多个用逗号分隔的表达式。

示例:

FileOpen(1, " c:\example.txt ", OpenMode.Output)

Printline(1)

Printline(1,”Hello,”)

Print(1,spc(4),”World!”)

FileClose(1)

Write/Writeline和print/printline类似



2.随机文件的操作

随机访问文件中的字节构成相同的一些记录,每个记录包含一个或多个字段,对于一个字段的记录对应于任一标准类型,随机访问文件中的所有记录都必须具有相同长度,如果实际字符串包含的字符少于将它写入其中的字符串元素的固定长度,则 Visual Basic 用空白(字符代码 32)填充记录中的尾随空格。如果该字符串长于字段大小,则 Visual Basic 截断它。

示例:用户定义数据类型:

Structure Person

Public ID As Integer

Public MonthlySalary As Decimal

<VBFixedString(15)> Public Name As String

<VBFixedString(2)> Public Sex As String

End Structure

其中VBFixedString用于定义字符串为固定长度的字符串。

在打开一个文件进行随机操作访问前,应该定义一个类型该类型对应该文件已包含或未包含的记录。

打开要进行随机访问的文件:

FileOpen 函数:FileOpen(FileNumber, FileName, OpenMode.Random, , , RecordLength)

FileNumber 和 FileName 分别指定要打开的文件的编号和文件名。RecordLength 以字节为单位指定每条记录的大小。如果 RecordLength 小于写入文件的记录的实际长度,则会生成错误。

示例:打开随机访问的文件。

Dim FileNum as Integer ,RecLength as Long, Aperson as Person

‘计算记录的长度

RecLength=Len(APerson)

‘获得可用的文件号

FileNum=FreeFile()

‘打开文件

FileOpen(FileNum,”c:\example.txt”,OpenMode.random,,,Reclenght)

打开文件之后就可以把记录读入变量中,使用FileGet函数。

示例:从文件中读取第一条记录

Dim FileNum as Integer ,RecLength as Long, Aperson as Person

RecLength=Len(APerson)

FileNum=FreeFile()

FileOpen(FileNum,”c:\example.txt”,OpenMode.random,,,Reclenght)

FileGet(FileNum,Aperson,1);

Console.WriteLine(Aperson.Id)

Console.WriteLine(Aperson.Name)

Console.WriteLine(Aperson.Sex)

Console.WriteLine(Aperson.MonthlySalary)

FileClose(FileNum)



写入记录:通过FilePut函数来替换已经存在的记录或新增记录[转]全面剖析VB.NET技术(完整篇)

示例:写入五条记录到文件中:

‘自定义数据类型

Structure Person

Public ID As Integer

Public Name As String

End Structure

Sub WriteData()
Dim MyRecord As Person
Dim recordNumber As Integer
' 随机方式打开.
FileOpen(1, "C:\example.txt", OpenMode.Binary)
For recordNumber = 1 To 5 '
MyRecord.ID = recordNumber ' Define ID.
MyRecord.Name = "My Name" & recordNumber '创建一个字符串
FilePut(1, MyRecord) ' 写入文件
Next recordNumber
FileClose(1)
End Sub
以上代码实现了随机访问的方式打开文件,并写入记录。



二进制文件的操作

打开要进行二进制访问的文件

FileOpen(FileNumber, FileName, OpenMode.Binary)

关闭要进行二进制访问的文件

FileClose(FileNumber)

如果保持较小的文件大小很重要,则采用二进制访问。因为二进制访问不要求固定长度的字段,所以类型声明可以省略字符串长度参数。这使得以通过生成变长记录来节省磁盘空间。使用二进制型访问的类型定义为:

Structure Person

dim ID As Integer

dim Name As String

dim MonthlySalary As Decimal

dim Sex As String

End Structure

使用变长字段的二进制输入/输出的缺点是无法随机访问记录,而必须按顺序访问它们才能了解每条记录的长度。仍可直接转到文件中的指定字节位置,但是如果字段是变长的,则不知道哪个记录位于哪个字节处。 


二、语法
    很久以来,VB因为缺乏完善的面向对象支持、缺乏高效的错误处理机制和性能表现不佳,因而一直受到某些人的嘲笑。VB.NET将彻底改变这种情况。然而,VB.NET在这些方面的改进也要付出代价,许多旧的代码需要手工进行转换才能在VB.NET下运行。
  
    下面几个表格总结了VB.NET语言在语法上的改动之处。注意这些表格并没有完全列出所有改动之处,但列出了最重要的一些改动。
  
    表A对比了VB6中一些熟悉的语法形式及其在VB.NET中类似功能最接近的语法形式。
  
  表A:语法对比
  旧语法 新语法 说明
  窗体装载事件,类初始化事件 Sub New procedure Sub New称为构造方法(Constructor),它可以有参数。
  Property Let Property Set Let关键词不再有效。
  Currency Decimal 在VB6中,Decimal是Variant的一种子类型,但在.NET中它是一种固有的数据类型。.NET不再支持Currency数据类型。
  Variant Object VB.NET的Object数据类型兼有VB6 Object类型和Variant类型的能力。
  Debug.Print Debug.Write Debug.WriteLine 这个变化只是名称上的简单变化:从Print变为Write和WriteLine。
  Wend End While VB.NET推荐使用While循环而不是Do循环。
  
  
    为了让VB的数据类型和其他.NET语言的数据类型相匹配,Microsoft修改了整数类数据类型的表示方法,并加入了一个新的数据类型。这些改动对于进行外部调用的方法尤其重要(比如API调用)。例如,如果被调用函数需要一个32位的整数参数,则在VB6中它应该声明为Long,在VB.NET中应该声明为Integer。
  
  表B:和整数有关的数据类型
  长度 VB6以及更早版本中的名称 VB.NET中的名称
  16 bit Integer Short
  32 bit Long Integer
  64 bit (无) Long
  
  
    在VB.NET中,Microsoft减少了许多原先用于VB6的关键词,代之以“框架类”。之所以要进行这种替换,是因为框架类中的功能对所有的.NET语言都有效。下表列出了部分受影响的关键词。
  
  表C:被替换的关键词
  VB关键词 VB.NET名称空间中的位置 方法/属性
  Circle System.Drawing.Graphics DrawEllipse
  Line System.Drawing.Graphics DrawLine
  Atn System.Math Atan
  Sgn System.Math Sign
  Sqr System.Math Sqrt
  Rnd Microsoft.VisualBasic.Compatibility.VB6 Rnd
  Round Microsoft.VisualBasic.Compatibility.VB6 Round
  Lset System.String PadRight
  Rset System.String PadLeft
  DoEvents System.Winforms.Application DoEvents
  VarType System.Object GetType(返回类Type的对象,其中包含了可提取出信息的属性)
  
  
    在VB.NET中,变量、数组的声明和初始化方法都有所变化,下表概要地列出了VB.NET在这方面的变化。
  
  表D:新的声明方法
  变化 语法举例
  单个声明语句中不能声明多种类型。 'VB.NET不允许出现下面这种声明!
  Dim nCount As Integer, bAnswer As Boolean
  声明变量时可赋予初始值 Dim nCount As Integer = 20
  Dim nDoubleCount as Integer = nCount * 2
  允许为数组元素指定初始值 Dim nIndex(3) As Integer = (3, 5, 7)
  不能用Redim进行声明,只能用Redim重新定义数组大小。 '下面这行代码在VB.NET中不合法!
  Redim sName() As String
  
  
    大量新关键词实现了VB.NET中的新功能。下面是一些最重要的关键词及其用途、用法简例。
  
  表E:VB.NET的新关键词
  关键词 用途 简单例子
  Inherits 指向基类,用于实现继承。 Inherits System.WinForms.Form
  MyBase 在子类的代码中,MyBase引用基类。 StringProperty = MyBase.StringProperty
  Shared Shared表示类的所有实例共享类里面的变量。 Public Shared BaseLocation As String
  Try
  Catch
  Finally
  Throw 这是新的错误处理关键词。Try开始一个启用错误控制的代码块,Catch标识一个对特定错误进行处理的代码块,Finally开始一个不管错误是否出现都必须执行的代码块,Throw抛出一个错误(类似于VB6的Err.Raise)。 Try
  rsRecordset.Update
  Catch
  LogError ("更新失败!")
  Finally
  rsRecordset.MoveNext
  End Try
  ReadOnly 在属性声明中,ReadOnly指示一个只读的属性(只有Get过程的属性)。 Public ReadOnly Property
  StringProperty() As String
  WriteOnly 在属性声明中,WriteOnly指示一个只能写入的属性(只有Set过程的属性)。 Public WriteOnly Property
  StringProperty() As String
  Char 这是VB.NET中的单字符数据类型。 Dim chrInitial As Char
  Imports 在当前代码模块中引入指定类。 Imports System.WinForms
  Namespace 为模块指定名称空间(Namespace)。 Namespace MyApplicationName
  Overloads 重载。Overloads表示同一个函数名字有多个版本的实现,编译器通过函数的参数列表区分它们。 '同一个模块之内包含如下多个声明...
  Overloads Sub Display(sIn as String)
  Overloads Sub Display(nIn as Long)
  Overrides 覆盖。Overrides表示成员函数覆盖当前类所继承的基类中的指定方法。 Inherits MyBaseClass
  Overrides Function Name(nID as Long) _
  As String
  Overridable Overridable表示任意从当前类继承的类都可以覆盖指定成员函数。 Overridable Function Name _
  (nID as Long) As String
  MustOverride MustOverride表示任意从当前类继承的类都必须覆盖指定成员函数。 MustOverride Function Name _
  (nID as Long) As String
  Protected Protected表示成员函数只能从当前类的派生类访问。 Protected Sub Clear()
  
  
    在以前的VB中,直至VB 4为止, Let、Set和Get属性过程是分离的。VB.NET把同一属性的属性过程放到了一起:
  
  
  Private msMyStringProperty As String
  ' 声明区
  Public Property MyStringProperty As String
  Get
  MyStringProperty = msMyStringProperty
  End Get
  
  Set
  msMyStringProperty = MyStringProperty
  End Set
  End Property
  
  
  
    VB.NET不再有Let属性过程,因为所有赋值语句的语法(无论是对象还是非对象)都已经一样。
  
    语言方面的改动远远超过了对体系结构的改动。对于大多数人来说这些改动都有意义,但仍有人对某些改动存有异议。例如,在以前的版本中,许多任务可以用多种不同的方法完成,统一的编码标准要么不存在,要么很难执行。为了“清理”VB语言,Microsoft对VB作了一些重大的改动,许多以前可以有多种实现方法的任务现在只有一种方法。
  
    除了前面几个表格列出的内容之外,下面是一些特别需要注意的地方。
  
    首先,向过程参数传递数据的默认方式由原来的传递引用(ByRef)变成了传递值(ByVal),这是一个很重要的改动。通过引用传递参数比通过值传递参数面临着更多的危险,这种危险在于被调用过程可能无意地改变参数的值。VB.NET仍旧允许以引用方式传递参数,但默认参数传递方式的改变意味着程序必须作相应的调整。
  
    第二,VB.NET中不再有Set语句,把对象引用赋给变量现在只需一个等号就可以了,对象可以象任何其他值一样对待。虽然省略Set简化了代码,但也有一个附带的影响:默认属性不再有效。例如,下面这种属性值引用方法不再合法:
  
  
  Text1 = "这是对象的默认属性值。"
  
  
  
    相反,属性值必须按照如下方式显式引用:
  
  
  Text1.Text = "这是对象的默认属性值。"
  
  
  
    从表面上看来,VB.NET作这种要求似乎没有必要。但事实上,它对于摆脱默认属性来说却是必要的。例如,假设有一个名字为objFoo的对象变量,由于没有了Set语句,假若属性值仍旧可以象原来一样引用,下面这个语句到底是什么意思就很难确定了:
  
  
  objFoo = Text1
  
  
  
    这个语句是设置了一个对Text1的引用,还是把Text1的Text属性值赋给了objFoo?我们无法作出判断,编译器也同样不能判断。因此,抛弃Set语句也就意味着必须放弃默认属性值。
  
    .NET中最不让人喜欢的改动:Microsoft改变了一些早就在使用的数据类型的含义。在.NET中,Integer变成了32位,而Long则是64位。可以想象,这种改变将导致程序员频繁地用错变量类型。例如,调用某个API函数时应该使用16位的Integer还是使用32位的Integer?但愿Microsoft能够重新考虑这个决定,采用一些新的变量类型名字,如Int32和Long64。
  
    VB.NET引入了Option Strict关键词。Option Strict关键词用于替代Option Explicit。原来的VB允许把一个数字值赋给字符串变量,或者进行其它类似的不正常赋值操作,Option Strict结束了这种情况。声明Option Strict告诉Visual Basic.NET不要进行任何强制的类型转换。当然,VB.NET也不是完全限制了类型自动转换:它允许进行向下的自动类型转换(Cast),但不支持向上的自动类型转换。例如,如果不是使用“sngvariable = CSng(dblvariable)”这类语句进行显式的类型转换,声明为Single的变量不能设置为Double变量的值,因为它可能导致数据丢失;然而,Double变量可以直接设置为Single类型变量的值,且无需显式地进行类型转换,因为这里不存在数据丢失问题。使用Option Strict能够帮助开发者减少许多错误,包括许多难以调试的错误。附带说明:使用Option Strict时不允许再使用延迟绑定(Late Binding)。 
三、完善的面向对象支持
    VB.NET提供了完善的面向对象编程支持,是一种真正的OO语言。
  
    完善的面向对象支持应该包括封装(Encapsulation),继承(Inheritance)和多态性(Polymorphism)。当前的VB6已经部分地实现了这些支持,但仍因某些地方未能符合标准而受到责难。
  
    封装是指对象只显露公用的方法和属性。VB6已经提供了健壮的封装支持,具体通过Public和Private关键词实现,这两个关键词既可以用于方法,也可以用于属性。VB.NET进一步完善了VB6的封装支持,增加了一个Protected关键词。
  
    多态性即为“多种形态”,VB从4.0开始已经提供多态性支持,它在VB.NET中没有什么变化。然而,由于VB.NET中类支持两种类型的继承——接口继承和实现继承,多态性将有更广泛的用途。
  
    VB6已经支持一种称为接口继承(interface inheritance)的继承形式,VB.NET支持实现继承(implementation inheritance)完善了继承机制。过去,我们用VB的接口继承模拟实现对象继承,但现在不必再采用这种模拟技术。正如其他面向对象的语言,在VB.NET中我们可以覆盖基类的方法和属性,也可以借助多态性创建出健壮的、可升级的组件。例如,假设有一个从基类Crane继承的ForkLift类,利用下面的代码可以覆盖基类中Lift方法的默认实现:
  
  
  Public Class ForkLift
  Inherits Crane
  
  Overrides Sub Lift(ByRef _
  Height As Double)
  Height = Height + 10
  End Sub
  End Class
  
  
  
    VB.NET不仅允许覆盖方法或属性,而且还支持方法重载(Overload)。重载是一种定义具有相同名字、不同数据类型的方法或者属性的能力。例如,假设有一个对不同数据类型的数组进行排序的组件,我们无需为它定义多个排序方法的名字(每种数据类型一个方法名字);相反,我们可以重载单个方法名字:
  
  
  Overloads Sub SortArray(ByRef _
  aValues()As String)
  ...
  Overloads Sub SortArray(ByRef _
  aValues() As Integer)
  ...
  Overloads Sub SortArray(ByRef _
  aValues() As Object)
  
  
    在VB.NET中,窗体以类模块形式出现。它意味着类本身包含了所有构造窗体所必需的代码。你可能会奇怪为什么VB.NET中会看到这些代码而以前不行,事实上这个变化带来了许多强大的新功能,比如继承这些窗体的能力。Microsoft称这种技术为“可视化继承”(Visual Inheritance)。假设我们为大多数对话窗口设计了一个标准的格式,比如窗体某一边有一列按钮、某个角上有一个LOGO图标,可视化继承使得我们能够设计一个窗体模板(类),需要时只需从这个基类继承就可以得到新的对话窗口。

四、对象的广泛应用
    代码重用简化了开发过程,而可视化继承之类的功能又使得代码重用更加方便。然而,代码重用并不局限于此。借助作为VB.NET基础的CLR(Common Language Runtime,公共语言运行时环境),我们可以在VB.NET中继承其他VS.NET语言编写的类。例如我们可以编写一个C#类,然后在VB.NET类中继承该C#类。
  
    VB.NET的面向对象功能已经向各个方向扩展,甚至深入到了语言本身——在VB.NET中,一切都是对象。它意味着和以前的VB版本相比,我们从VB.NET本身获得的支持和功能要多得多,求助于Windows API的时候将更少。例如,在以前的VB版本中,我们用LoadPicture方法装入一个图形,用Line方法(或者其他速度更快的API函数)画线;而在VB.NET中,我们用System.Drawing对象创建和处理图形。下面这段代码用System.Drawing对象在窗体上显示一个图形:
  
  
  picshowpicture.Image = _
  system.Drawing.Image.FromFile( _
  "c:test.bmp")
  
  
  
    注意,VB.NET的“一切都是对象”可能会使代码变得冗长。考虑下面这个语句,它在一个图形对象上面画一条黄绿色的线:
  
  
  objgraphics.DrawLine(system.Drawing. _
  Pens.Chartreuse, 0, 0, 100, 100)
  
  
  
    语句虽然变长,但它获得的好处是:更加灵活,更加容易使用。以前,要实现一些较为复杂的功能往往要深入研究文档,通常还要求助于API。现在,所有相关的功能集都封装到了对象之中。用对象封装功能还有额外的优点——对象以一种极为优美的形式把相关功能组织了起来,所以浏览各个对象、看看它们到底做些什么,事实上也是一件有趣的事情。
  
    Visual Basic.NET的面向对象特色带来了许多切实的好处。大多数情况下,和以前的VB版本相比,VB.NET面向对象的本性以及它对继承的支持使得创建某些类型的应用更加快速和方便。然而,虽然我们可以使用继承以及其他.NET的新功能,比如自由线程,但这些功能并不是一定得使用不可。正如所有其它语言的功能,我们必须使用的功能是那些对给定情形来说最具有意义的功能。
  
    自由线程或许有必要特别说明。VB6允许通过单元线程创建多线程的服务,但VB从来没有支持过创建自由线程的客户程序。VB.NET改变了所有这一切。现在,创建自由线程的应用已经是一件非常平凡和普通的事情。它是如此平凡,以至于完全可以预料有些程序员在为应用加入自由线程时不会理解它的具体细节。启动新的线程只要很少的几行代码——只需把方法的地址传递给线程对象,该方法就会启动一个新的线程。这无疑极为实用和方便,但必须注意的是:这些功能只适合特定的情形,了解哪些情形适用这些功能以及如何恰到好处地运用这些功能属于开发者自己的责任。坦率地说,许多开发者会因为滥用继承和自由线程而给自己带来麻烦,希望这中间并不包括你。


五、公共运行时环境
    迄今为止,业界对VB.NET讨论得最多的特色或许就是CLR。VB.NET运行在CLR之上,正是CLR为VB.NET带来了许多关键的新特色(包括缺点在内)。例如,CLR使得VB.NET支持跨语言的继承以及自由线程。
  
    在VB6中,分布式VB程序要求有VB运行时库msvbvm60.dll支持,即该运行时库必须随同应用一起分发。其他许多语言,比如C++和Java,也有类似的要求。在.NET中,所有Visual Studio语言共享同样的运行时环境CLR。改用CLR带来了几个重要的结果:现在所有Visual Studio语言都共用同样的IDE、同样的窗体引擎、同样的异常处理机制,等等。它意味着Visual Basic在很大程度上已经可以和.NET的其他语言相提并论,如C#等。然而,对于CLR的异议仍旧存在,VB业界仍在激励地争辩它地价值。
  
    不管应用是用VB、C#还是其他.NET语言编写,所有VS.NET代码都是编译成中间语言(Intermediate Language,IL)。当应用运行时,一个实时编译器(just-in-time compiler,或称为JIT)就把IL代码编译成机器语言。在理论上,它意味着为非Windows的平台构造.NET运行环境是可能的,但目前还没有出现有关这类系统的正式消息。IL有一个缺点:正如VB在5.0以前的版本,IL代码对于类似的反向编译工程很敏感。由于存在这种可能性,许多开发者对于.NET框架的整体安全性抱有怀疑。
  
    对CLR进行优化影响IL层次上的代码,它使得所有使用CLR的语言受益。然而,对于特定语言的优化涉及到如何把代码编译成IL代码,它根据特定语言的语法进行。因此,.NET各种语言之间存在一定的性能差异是必然的。但不管如何,从整体上来看这仍旧是好事,例如CLR为VB带来了和C#一样的调试和分析工具——之所以能够如此,是因为它们都使用一样的工具。
  
    CLR提供了前所未有的跨语言集成能力,其中包括跨语言继承代码的能力。所有使用CLR的语言都使用一个公共类型系统(Common Type System),它使得开发那些运用多种语言的应用变得更为容易。
  
    在CLR之内运行的代码称为“受管理的代码”(Managed Code),受管理代码所使用的内存由CLR全面控制。受管理的代码有着许多优点,包括交叉语言集成、跨语言异常控制以及一个组件交互的简化模型。Visual Basic.NET只能以受管理代码方式运行,与此相对应,C#却具有将代码转入非受管理方式运行的能力(运行在CLR之外),比如执行指针处理之类的操作。这是VB.NET不能与C#相提并论的地方之一。然而,这种能力的是否重要,对于不同的人、不同的用途来说都有所不同。
 
由CLR导致的体系上的不同不仅仅是跨语言继承、共享功能和受管理代码,它还有更深刻的意义。Visual Studio.NET的底层体系不再是COM;另外,VB.NET中所有东西都是对象,甚至连字符串也一样。由于这些原因以及其他许多原因,Microsoft改变了底层体系管理对象的方法。COM系统通过引用计数方式管理对象,每当对象被引用时,引用计数就增加。当对象引用超出作用范围或者被释放时,计数器的值就减少;一旦引用计数为0,对象就被释放。Microsoft声称.NET体系中的引用计数开销实在太大,使得.NET采用引用计数不再合适,因此它就放弃了引用计数,改用垃圾回收(Garbage Collection)。
  
    大约40年前,John McCarthy设计了LISP语言,它是可考证的第一种编程语言。LISP运行时不断地分配和释放大量的小块内存,由于那时的计算机内存远远没有现在这么庞大,因此早期的LISP用户很快感到内存不足,同时许多不再使用的内存却未能利用起来。为了解决这个问题,McCarthy于1959年第一次提出了垃圾回收的思想。
  
    在一个真正面向对象的系统中,垃圾回收机制能够很好地满足分配和释放大量小块内存的需要。因此,Microsoft在VS.NET中重新实现了垃圾回收机制。
  
    CLR垃圾回收器(CLR Garbage Collector)的主要任务就是监视程序使用的资源,当可用资源达到某个确定的极限时查找不再使用的对象,如发现有这类对象存在则释放它们所占用的资源。垃圾回收的一个很大的优点是程序员无需再为大多数常见的循环引用担心。在循环引用情形下,子对象拥有对父对象的引用,同时父对象又拥有对子对象的引用。在引用计数模式下,循环引用阻止了系统释放和拆除任意一个对象。然而,垃圾回收器能够找出这类循环引用并拆除它们。垃圾回收机制同时也意味着,当对象的最后一个引用被释放时,对象并不一定立即被拆除。
  
    采用垃圾回收机制的一个后果是:我们不能再希望类的Terminate事件总是适时触发。事实上,如果线程被阻塞的话,Terminate事件可能完全不会触发。这就是所谓的“非确定的结束”(non-deterministic finalization),而COM提供的则是“确定的结束”。由于缺乏“确定的结束”,再加上因为垃圾回收器重新组织和整理内存导致不能运用指针,新闻组中出现了对该问题激烈的争论:有些人憎恨这些新的限制,因为他们依赖于“确定的结束”;有些人觉得无关紧要,因为他们并不依赖于Terminate事件。
  
    从引用计数转变到垃圾回收仅仅是Visual Studio.NET底层体系不再是COM这一变化的诸多必然结果之一。虽然VB.NET之内仍旧可以使用COM对象,但这些对象必须通过封装(Wrapper)才能访问。任何时候,封装都意味着性能的降低,甚至还有可能导致对象行为的异常。如果要迁移一个大量使用COM对象的工程,你必须认真地进行计划和测试,应用程序的某些部分可能还需要重新构造。


七、面向Web的支持
    除了Windows Forms新引擎之外,.NET还包含了一个专门为构造Web窗体设计的窗体引擎,称为Web Forms。这个引擎的目标在于让用户能够象创建传统Windows桌面应用的窗体一样方便地创建Web窗体。Web Forms是一种ASP.NET技术,通过它我们可以使用熟悉的RAD(快速程序开发)工具构造出带有执行代码的窗体。不过,窗体中的ASP.NET代码以编译方式在服务器端运行,经过处理后把结果HTML发送给支持HTML 3.2的浏览器。
  
    客户端事件数据由底层框架截获并发送到服务器。这意味着应用界面不再受浏览器类型的约束,意味着有大量UI工具可供使用,意味着用户可以充分发挥现有的窗体制作技巧。如果应用没有必要做到浏览器中立,那么它就可以利用IE浏览器的各种特色。有了Web Forms,我们将能够更轻松地为那些具有Web功能的应用构造出更好、更丰富的用户界面。
  
    VB.NET中另外一个面向Web的重要特色是Web服务。在Microsoft的宣传中,Web服务被推崇为之所以要采用.NET技术的重要理由之一。事实上,从根本上来说Web服务是一种类似COM的、通过Web服务器和标准协议发布的对象。当然,Web服务并不是严格意义上的COM对象,但两者作用方式类似。Microsoft期待着各类公司都以Web服务方式提供服务,期待着未来创建应用时只需简单地“粘合”各种服务,就象今天借助Office和支持VBA的应用通过VBA构造新应用一样简单快捷。
  
    从Microsoft PDC(Professional Developers Conference,专业开发者大会)的一个演示中,我们可以看出Microsoft希望开发者如何粘合各种Web服务。在这个演示中,一个假想的医生以Web服务形式发布其时间表,示范如何通过Web用智能电话和医生订立约会。Visual Basic.NET还允许查询服务器,提取服务器支持的所有服务的元数据。Web服务描绘了Microsoft野心勃勃的战略,然而,唯有时间才能告诉我们Microsoft是否在大范围推广Web服务上取得了成功。但不管如何,这个想法本身看来有着美好的前途。
  
    为了减少与封装和分发应用有关的问题,如令人畏惧的DLL Hell问题(在共享DLL的应用之间,由于一个应用的升级而导致另一个应用无法正常运行的情况),Microsoft作出了种种努力,它同样也带来了美好的希望。所有.NET应用都封装为程序集(Assembly)。程序集包含了描述各种运行需求的元数据。这种元数据称为manifest,其中包括:程序集的标识信息(名称,版本等),列出了所有文件依赖关系以及文件位置和文件版本的文件清单,外部依赖信息(带有描述程序集必须用到、但开发者没有自己创建的DLL以及其他资源的数据)。程序集是通过manifest自我描述的,因此.NET应用的运行并不需要修改注册表。换句话说,.NET应用不再要求注册组件。在最理想的情况下,客户机器上已经有了.NET运行环境,部署一个复杂的应用简单到只需复制一个文件夹到目标机器。使用程序集的另外一个优点是:不同的应用可以拥有同一DLL的不同版本,所有这些应用都互不干涉地在同一台机器上运行。如果它能够按照预期那样获得成功,DLL Hell和可怕的版本问题都将成为历史。
   [转]全面剖析VB.NET技术(完整篇)
    Visual Basic.NET代表着VB的一次重大飞跃。尽管如此,把VB.NET看成是一种有着熟悉语法的新语言而不是对旧语言的简单升级或许是对待VB.NET较为正确的心态。


群贤毕至

访客