在 Visual Basic 中组织代码
最后修改于 2023 年 10 月 18 日
在 Visual Basic 教程的这一部分,我们将展示如何组织代码。我们将涵盖模块、过程、命名空间和作用域。
Visual Basic 语句被组织成块、模块、类和命名空间。这有助于使代码更易于维护和健壮。正确的代码组织可以防止在代码中出现错误。
Visual Basic 程序的基本构建块是
- 程序集
- 命名空间
- 模块
- 类
- 过程和函数
- 块
- 语句
程序集 是一个 DLL 或 exe 文件。程序集是一个已编译的代码库,用于部署、版本控制和安全。一个 命名空间 是一个抽象容器,为项目提供上下文。一个 模块 是一个可在其命名空间中使用的引用类型。类是 OOP 程序的基本构建块。一个 过程 是一个程序的单元,用于执行特定任务。一个 块 是 Visual Basic 语句的最低级别组织,由一些关键字(如 If 或 While)提供。一个 语句 是 Visual Basic 程序中的一个原子,是代码的最小单元。
与此主题密切相关的是变量的作用域和持续时间。一个 作用域 是已声明变量的可见性。
| 范围 | 描述 |
|---|---|
| 块作用域 | 仅在声明它的代码块中可用 |
| 过程作用域 | 在声明它的过程中可用 |
| 模块作用域 | 对声明它的模块、类或结构中的所有代码可用 |
| 命名空间作用域 | 对声明它的命名空间中的所有代码可用 |
一个变量的 生命周期 是变量保存值的时间段。局部变量存在于过程执行期间。之后,它们将不再可用。但是,如果我们将一个变量声明为 Static,则该变量在过程终止后将继续存在。模块、共享和实例变量的生命周期与应用程序的生命周期相同。
基本示例
首先,我们介绍一些基础知识。
Option Strict On
Module Example
Sub Main()
Console.WriteLine("Simple example")
End Sub
End Module
在此示例中,我们有一个名为 Example 的模块。在示例中,我们有一个 Main 子例程。将某些消息打印到控制台的语句放在 Main 过程中。即使是最简单的 Visual Basic 程序也必须正确组织。
Option Strict On
Public Class Example
Public Shared Sub Main()
Console.WriteLine("Simple example")
End Sub
End Class
确切的例子,现在没有模块。我们也可以将代码放入一个类中。 Main 过程必须声明为 Shared,因为该类没有被实例化。编译器在不创建类的实例的情况下调用 Main 方法。这就是为什么它必须声明为 Shared 的原因。Java 和 C# 的工作方式相同。
命名空间
命名空间用于在最高逻辑级别组织代码。它们对暴露给其他程序和应用程序的编程元素进行分类和呈现。在命名空间中,我们可以声明另一个命名空间、一个类、一个接口、一个结构、一个枚举或一个委托。
在以下代码中,我们有两个共享同一命名空间的文件。
Option Strict On
NameSpace ZetCode
Module Example1
Public Dim x As Integer = 0
Sub Init()
x += 100
Console.WriteLine(x)
End Sub
End Module
End NameSpace
我们有一个 ZetCode 命名空间。在命名空间中,我们有一个模块 Example1。
NameSpace ZetCode
我们声明一个名为 ZetCode 的命名空间。
Public Dim x As Integer = 0
在模块中,我们声明并初始化一个 x 变量。
Sub Init()
x += 100
Console.WriteLine(x)
End Sub
我们有一个 Init 方法,我们在其中使用 x 变量。
Option Strict On
NameSpace ZetCode
Module Example
Sub Main()
Init()
x += 100
Console.WriteLine(x)
End Sub
End Module
End NameSpace
在第二个文件中,我们使用上一个文件中的 Init 方法。
NameSpace ZetCode
我们在同一个命名空间中工作。
Init() x += 100 Console.WriteLine(x)
我们调用 Init 过程并使用 x 变量。过程和 x 变量都在不同的文件和不同的模块中定义。但是它们在同一个命名空间中定义,所以我们可以使用它们。
$ dotnet run 100 200
以下代码示例有两个不同的命名空间。我们使用 Imports 关键字从不同的命名空间导入元素。
Option Strict On
NameSpace MyMath
Public Class Basic
Public Shared PI As Double = 3.141592653589
Public Shared Function GetPi() As Double
Return Me.PI
End Function
End Class
End NameSpace
我们在 MyMath 命名空间中有一个 Math 类的框架。在 Basic 类中,我们定义了一个 PI 常量和一个 GetPi 方法。
Option Strict On
Imports MyMath
NameSpace ZetCode
Public Class Example
Public Shared Sub Main()
Console.WriteLine(Basic.PI)
Console.WriteLine(Basic.GetPi())
End Sub
End Class
End NameSpace
在此文件中,我们使用 MyMath 命名空间中的元素。
Imports MyMath
我们将 MyMath 命名空间中的元素导入到我们的命名空间中。
Console.WriteLine(Basic.PI) Console.WriteLine(Basic.GetPi())
现在我们可以使用这些元素了。在我们的例子中是 PI 变量和 GetPi 方法。
Option Strict On
' Imports MyMath
NameSpace ZetCode
Public Class Example
Public Shared Sub Main()
Console.WriteLine(MyMath.Basic.PI)
Console.WriteLine(MyMath.Basic.GetPi())
End Sub
End Class
End NameSpace
请注意,我们不需要 Imports 关键字。在示例中,它被注释掉了。我们可以通过使用元素的完全限定名称来使用来自其他命名空间的元素。
模块
一个模块用于组织代码,并包装类似使用的变量、属性、事件和过程。与类不同,模块不是一个类型。可以在命名空间或文件中创建模块。不能在另一个模块、类、结构、接口或块中创建模块。模块中的所有成员都隐式为 Shared。模块具有 Friend 访问权限。这意味着模块可以在程序集的任何地方访问。
Option Strict On
Module First
Public x As Byte = 11
Public Sub FirstModule()
Console.WriteLine("First module")
End Sub
End Module
Module Second
Public y As Byte = 22
Public Sub SecondModule()
Console.WriteLine("Second module")
End Sub
End Module
Module Example
Sub Main()
Console.WriteLine(x)
Console.WriteLine(Second.y)
FirstModule()
SecondModule()
End Sub
End Module
我们定义了三个模块。前两个模块有变量和过程。这些将在第三个模块中使用。
Module First
Public x As Byte = 11
...
End Module
我们也可以在模块中使用访问说明符。这样,我们可以控制模块中元素的访问性。
Console.WriteLine(x) Console.WriteLine(Second.y)
我们打印 x 和 y 变量。它们是 Public 的,可以从不同的模块中访问。我们可以使用模块名称来完全指定变量名。
一个 作用域 是一个变量的可见性。具有模块作用域的变量在其声明的模块中可用。
Option Strict On
Module Example
Private x As Integer = 0
Sub Main()
proc1()
proc2()
proc3()
End Sub
Sub proc1()
Console.WriteLine(x)
End Sub
Sub proc2()
x += 100
Console.WriteLine(x)
End Sub
Sub proc3()
x += 100
Console.WriteLine(x)
End Sub
End Module
我们在模块中有 x 变量。该变量在所有三个过程中都可用。
Private x As Integer = 0
这是一个具有模块作用域的变量。它在任何过程之外声明。
Sub proc2()
x += 100
Console.WriteLine(x)
End Sub
在 proc2 过程内部,我们增加 x 变量并将其内容打印到控制台。我们指的是在模块中定义的 x 变量。
$ dotnet run 0 100 200
过程
过程为代码项目提供了模块化。它们应该只执行特定的任务。
Option Strict On
Module Example
Dim x As Integer = 0
Sub Main()
Console.WriteLine(x)
proc1()
proc2()
proc3()
End Sub
Sub proc1()
Dim x As Integer
x += 100
Console.WriteLine(x)
End Sub
Sub proc2()
Dim x As Integer
x += 100
Console.WriteLine(x)
End Sub
Sub proc3()
Dim x As Integer
x += 100
Console.WriteLine(x)
End Sub
End Module
在前面的代码示例中,除了主过程之外,我们还有三个过程。这三个过程创建了一个局部 x 变量并将其打印到终端。主过程引用模块 x 变量。
Sub proc1()
Dim x As Integer
x += 100
Console.WriteLine(x)
End Sub
proc1 过程创建了一个局部 x 变量。此变量 遮蔽 了在模块作用域中声明的那个变量。
$ dotnet run 0 100 100 100
主过程打印 0。其他过程打印 100 到终端。它们创建了它们自己的局部 x 变量,将它们初始化为 0,并增加 100。
块作用域
重要的是要理解,在 If/End If 或 While/End While 等代码块中声明的变量具有有限的块作用域和生命周期。下一个例子说明了这一点。
Option Strict On
Module Example
Sub Main()
If True
Console.WriteLine("Inside If block")
Dim x As Integer = 0
Console.WriteLine(x)
x += 500
Console.WriteLine(x)
End If
Console.WriteLine("Outside If block")
Rem Will not compile
Rem Console.WriteLine(x)
End Sub
End Module
我们在 If/End If 块内声明了一个 x 变量。
Rem Will not compile Rem Console.WriteLine(x)
该变量在块外部不可用。如果我们取消注释第二行,该示例将无法编译。
Visual Basic 教程的这一部分专门用于组织代码。