VB.NET

**Visual Basic .NET**（**VB.NET**）是.NET 框架和後來的.NET 下的一種多重編程範式高階語言。

VB.NET，是微軟公司於 2002 年作為原有的 Visual Basic 的繼承者而推出。雖然自 2005 年起，語言名稱中的「.NET」就已經被去掉了。但為了與 VB 6.0 及以前版本的 Visual Basic 進行區分，「Visual Basic .NET」的名字仍然被社會公眾用來指代 VB 7.0 及以後的 Visual Basic。VB.NET 與 C# 同為.Net Framework 框架下兩種主要的程式設計語言，都是為了呼叫.Net Framework 的類別館資源，因此兩種語言具有很高的對應性，資料類型、控制結構與語言特性都存在一一對應，容易把原始碼從一種語言對譯為另一種語言。

微軟公司的整合式開發環境 Visual Studio 是最為廣泛使用的 VB.NET 開發工具。然而 Visual Studio 的大部分版本都是價格不菲的商業軟體，除了 Express 版本和 Visual Studio Community（以上兩者皆為免費軟體）。除了 Visual Studio，SharpDevelop 和 Mono 也是可用的 VB.NET 開發環境。

## 資料類型與字面常數表示

VB.Net 的資料類型，實際上是.Net Framework 定義的資料類型。

此外，還有 SByte、UShort、UInteger、ULong 等無符號資料類型。

&O123 表示八進位；&H123 表示十六進位。

## 語法特性

VB 使用的名字是大小寫不敏感的。但是，CLR 是大小寫敏感的。所以建議保持一致的大小寫。

### 空值

VB 自版本 5 以後的資料類型來源於 COM，而其根源是 OLE 資料類型。

* Nothing（C# 的 null）表示 Object 類型的變數（即 COM 中的 IDispatch 指標，VB 中的所有類和控制項均由 IDispatch 衍生）為空。對於參照型變數，表示未繫結到一個物理實體物件。
* Empty 表示 VARIANT 類型變數未初始化（即 COM 中的 VARIANT 結構體中的 VT 成員值為 VT\_EMPTY）。
* Null 表示 VARIANT 類型變數已初始化，其值為 Null，這時 COM 中的 VARIANT 結構體中的 VT 成員值為 VT\_NULL。通常是所要表示的值不存在或者有問題不合規。實際上，一個參照型變數如果被賦值為 Null，則它繫結的位址為 0x0000
* 零長度字串（空字串）需要分配記憶體，只不過記憶體（即 COM 中的 BSTR 字串）頭 4 個位元組記錄的長度為 0。VB.Net 定義了一個 Public Shared Readonly Empty As String = ""。對於僅聲明但未實例化的 String 物件，實際上都繫結到 String.Empty 物件上。
* vbNullString 沒有分配資料記憶體，實際上定義為 Dim \*vbNullString As String = Nothing。但又規定了字串比較時 vbNullString = "" 為真。

在與空值做比較時，需要區分各種不同用法：

* 物件（參照型變數）是否為 Nothing，可用 IsNothing（物件名），物件名 Is Nothing，物件名 IsNot Nothing 等
* 在比較資料庫的一個欄位的值是否為空，在.Net 中應該用 IsDBNull 函式或 Convert.IsDBNull 方法。例如 IsDBNull (recordSet ("Column1").Value)) 或者 recordSet ("Column1").Value=DBNull.Value。因為 DBNull 是衍生自 Object 的一個類，DBNull.Value 是它的唯一的值。而資料庫中的欄位值，在 DataRow 中總是表示為 Object，永遠不可能為 nothing。
* 比較字串物件是否為空字串，實際上規定了下述三種是等效的：
  * 物件名 = ""
  * 物件名 = String.Empty
  * 物件名 = vbNullString

對於可空類型，實際上是 Nullable (Of T) 泛型結構。例如，下述三行等價：

```
Dim ridesBusToWork1? As Boolean
Dim ridesBusToWork2 As Boolean?
Dim ridesBusToWork3 As Nullable(Of Boolean)
```

比較表達式 someVar = Nothing 的結果永遠是 Nothing，應該用 someVar.HasValue () 方法去判斷是否為空，或者用 Is 或 IsNot 關鍵字。

### 陣列

陣列的下標開始自 0，這遵從了.NET 的標準。如果不指定陣列的下標上界，則為動態陣列，其長度可以動態調整。

### 結構控制語句

#### 分支語句

* If 語句

* Switch 語句

#### 迴圈語句

包括下述幾種：

* For...Next 迴圈

* Do 迴圈

或

* While 迴圈

* For Each...Next 迴圈

### Yield 語句

實現迭代器遍歷一個序列，每次取得一個返回值。迭代器可以作為一個方法或屬性的 get 存取器，其中的 Yield 語句返回迭代器的返回值，並記住當前執行的位置。下次再呼叫迭代器，從該執行位置恢復執行，直至迭代器代碼執行完或者遇到 Exit Function 或 Return 語句。編譯器把迭代器作為一個狀態機的類。

### 物件導向

物件導向時，類的聲明範例：

上述範例中的 Public 關鍵字表示可存取性 (accessibility)，表示可以被任意代碼存取；它可以替換為其他的可存取性：Private（僅限該 Class 自身存取）、Friend（僅限同一項目中的代碼存取）、Protected（僅限自身或衍生類別存取）、Protected Friend 等。如果使用 ReadOnly，則表示資料成員或屬性是唯讀；WriteOnly 表示只寫。Shadows 關鍵字表示覆蓋父類中同名（但不一定參數相同）的 Event。使用關鍵字 MyBase 參照基礎類別。

類可用繼承修飾詞：NotInheritable 關鍵字，表示該類不能做基礎類別；MustInherit 關鍵字，表示這是一個抽象類。

類的屬性與方法能否被覆蓋：Overridable 關鍵字表示可被覆蓋；Overrides 關鍵字表示覆蓋了基礎類別中同名的方法或屬性；NotOverridable 關鍵字表示不可覆蓋；MustOverride 表示方法或屬性僅聲明沒有實現，這時該類必須有 MustInherit 修飾詞，是一個抽象類或者介面，僅能包含屬性、方法、函式的聲明。

如同其他.Net 語，Visual Basic 不允許多重繼承，但可以同時實現多個 interface。

#### 介面（interface）

介面是一類特殊的抽象類，不能包括可執行代碼與類的資料成員的聲明：

介面中這些成員都強制是 Public 可存取性。

實現一個介面，使用 Implements 關鍵字：

#### 多型（Polymetric）

基於繼承的多型，是指用基礎類別類型的變數繫結不同的子類別物件，這樣呼叫基礎類別變數的方法，在執行時動態確定實際執行了哪個衍生類別的同名的方法。多型的優點是可以針對基礎類別（或介面）的方法來寫一個通用的過程或者資料容器，適用於各種不同的衍生類別的具體實現。

#### 委託（Delegate）

委託本質上是一種 Class，衍生自 System.Delegate，包含了三部分資料：一個類物件的位址、該物件所屬類的一個方法的位址，以及另一個委託的參照（reference）。前兩部分可以實現對一個類物件的方法的呼叫；第三部分把委託形成一個連結串列，使其依次被呼叫執行。如下聲明了一個委託：

```
 Delegate Sub PlayHandler(ByVal sender As Object, ByVal e As System.EventArgs)
```

委託常用於事件處理（Event Handler）。.Net Framework 的事件是類的屬性（實際上是一個巢狀類），用於封裝參數格式固定的委託；該委託的參數總是為 (ByVal sender As Object, ByVal e as System.EventArgs)，返回值為 void（即 Sub 類型）。例如：

```
 Public Class clsName
    Public Event monitor As PlayHandler
 End Class
```

對一個具體的實例，可以給它的事件在運行時動態追加上一個或多個事件處理函式：

```
 AddHandlerins.monitor, AddressOf playHandle_1
```

AddHandle 指向引發事件的物件；AddressOf 把一個函式或過程名轉化為一個隱式建立的委託實例，用於確定該事件物件所要呼叫的事件處理程式。在 AddressOf 關鍵字可隱式建立一個參照特定過程的委託的實例。

程式可以丟擲一個事件：

```
 Dim WithEvents e As New System.EventArgs
 Dim ins As New clsName
 RaiseEvent ins.monitor(ins,e)
```

#### using 語句

using 語句，定義一個範圍，在範圍結束時自動釋放物件所占用的資源。

```
Using conn As New SqlConnection'當在某個代碼段中使用了類別的實例，而希望無論因為什麼原因，只要離開了這個代碼段就自動呼叫這個類別實例的Dispose。
   '執行代碼
End Using
```

#### 自動屬性

例如：

```
Public Property pa As String=""
```

#### 物件初始化器

集合（Collection）物件的初始化與普通類物件的屬性初始化，分別使用 From 與 With 關鍵字。例如：

### 匿名類型

例如：

```
Dim people = New With {.name="kyo", .age=22}
```

### 匿名函式或 lambda 表達式

即無名的函式或過程，作為表達式的值。可以寫為一行或多行。例如：

```
Dim func1=Function(i As integer) i+10
Dim action = sub()
  End Sub
Dim func2 = Function()
  End Function
```

可以在聲明匿名函式的同時呼叫它。單行的 lambda 表達式不能使用 Return 關鍵字，其返回類型是自動推導得出；其參數要麼都是用 As 關鍵字指明類型，要麼全部是自動推導出類型。

lambda 表達式在定義時可以使用所在上下文（context，即 C++ 語言的閉包 closure）的局部變數、參數、屬性、Me 等等的值，即使 lambda 表達式離開了定義時所在的 context，這些被使用的局部變數等的值仍然有效。這是因為 lambda 表達式在定義時把所用到的 context 的值儲存到它自己的定義類中。lambda 表達式可以巢狀定義。

### 擴充方法

例如：

```
Imports System.Runtime.CompilerServices
<Extension()> Public Function funcName(ByVal ins As className) As String
    'Do something
End Function
```

### 例外處理

### LINQ

```
From element [ As type ] In collection [, element2 [ As type2 ] In collection2 [, ... ] ] [Where 表达式]
```

### 例子（Hello World）

這裡給出了一個 Hello World 的例子。通過它們您可以更好地理解 Visual Basic 的特性。（此原始碼執行於命令列下）

這個程式能輸出 _Hello World_。

第一行是模組定義，命名空間的定義一般可以省略。VB.NET 中，所有函式，過程與變數的聲明都必須在模組或者類的內部，而不能直接存在於命名空間內部。

第二行定義了名為 Main 的過程。一般來說，「Sub Main ()」是程式的入口點。

第三行輸出「Hello World」。

第四行結束了過程 Main 的定義。

第五行結束了模組 Mdl\_Main 的定義。

### 與舊版 VB 比較

與舊版 VB（VB 6.0 及以前）相比較，VB.NET 明顯受到了.Net Framework 中其他語言思想的影響。與舊版 VB 相比，VB.NET 更加嚴格而不失靈活。

* `Long` 類型與 `Integer` 類型的長度分別倍增，達到了 64 位元和 32 位元。
* 事件的處理過程不再依賴於名稱，而是通過 `Handle` 子句進行靜態繫結或者在執行時進行動態繫結。例如處理按鈕控制項 `Button1` 的 `Click` 事件：

Visual Basic 6：（注意此過程的名稱不可改變）

VB.NET：（注意此過程的名稱無關緊要）

* 很多原有的實現特殊功能的語句被相應定義好的函式替代。這減少了關鍵字的使用（如 `Open()` 函式取代 `Open` 語句，表單的 `Print()` 方法取代 `Print` 語句）。同時，被封裝好的、功能更強大的、通用於.Net Framework 框架的類被推薦用來取代原有的語句。
* 對一些更強大的語法特性的支援，如：LINQ，Lambda 表達式（Visual Basic 2010 起支援多行 Lambda）。
* 同樣使用 `:` 作為一行中分行的符號，`_` 作為續行符。但是 VB.NET 自 Visual Basic 2012 起允許在函式的定義與呼叫中不加 `_` 地用換行分隔各個參數。

### 與 C# 等 C 家族語言比較

與 C 家族語言相比，VB.NET 則較多保留了 VB 的特徵，比如：

* 與 C 家族語言統一使用 `{`、`}` 定義語句塊不同，VB.NET 每種語句塊都有對應的開頭與結尾。如 `If ... Else ... End If`，`Class ... End Class`。
* VB.NET 定義變數使用 `Dim` 關鍵字，同時使用 `Public`、`Private` 或 `Protected` 表明作用域時可以省略 `Dim`。
* VB.NET 表示變數類型的方式是在變數名後附加 `As Type`（Type 為變數類型），而 C 家族語言是在變數名之前書寫類型名，無論在定義變數時還是在函式與形參的聲明時都是這樣。
* VB.NET 中有沒有返回值的特殊子過程 `Sub`。VB.NET 中沒有 `void` 類型，C# 中返回值為 `void` 的函式對應了 VB.NET 中的 `Sub`。
* VB.NET 中有一種特殊的類型 `Module`，相當於 C# 中的 `static class`。

下面這兩份功能一致的代碼展現出了 VB.NET 與 C# 的很多不同之處：

* VB.NET：

* C#：

VB.NET 與 C# 同為.Net Framework 的兩大主力程式設計語言，儘管有著各種各樣的不同，兩者最終都編譯為 MSIL 並由 CLR 執行。兩者功能基本一致，並可以在.Net Framework 框架下方便地互相呼叫與協同開發。關於兩者的優劣一直見仁見智。

### 呼叫 C 語言函式的規範

C 語言編寫的 DLL 檔案，VB 在呼叫時，需要注意：對於 C 語言的陣列指標，在 VB 中呼叫時應將陣列的首元素傳遞給 DLL。不能直接傳遞陣列名，因為如果傳遞陣列名，VB 實際會傳一個複雜的結構類型給 DLL。C 函式無法確定陣列大小，通常用另一個參數指出陣列的大小。

## 歷史

### 2002 年 Visual Basic .NET（VB 7.0）

Visual Basic .NET（VB 7.0）是隨 Visual C# 和 ASP.NET 一起在 2002 年發布的最初始的 VB.NET 版本。C# 被大力宣傳為微軟對付 JAVA 的王牌，受到媒體極力關注。然而 VB.NET（有時被稱為 VB 7.0）影響面不廣，這導致 VB 社群之外很少人關注它。那些試用過此版 VB.NET 的人在層層幕布下發現一個強大卻艱深的語言，而且還有不少缺點，例如它的執行階段組件（Run-Time）比 VB6 大了十倍，記憶體使用量也大大增加。

VB 7.0 引起了廣泛的爭議，主要原因在於對舊版 VB 的改動過大。許多資深的 VB 程式設計師抱怨 VB.NET，因為 VB.NET 2002 丟掉了許多不再發行的 VB6 中使用的大量語言結構和使用者介面功能，並且對保留下來的東西也改變了語意。例如，在 VB.NET 參數預設是以值方式傳遞的，而不是以參照方式。VB.NET 2002 被半嘲諷半認真地稱為 Visual Fred 或 VB DOTNOT。作為對 2005 年 3 月 8 日微軟拒絕為 VB6 再提供維護與支援的回應，當月月底出現了反對者的請願。

VB.NET 的支持者們認為新語言在很多方面比舊版本更為強大，比如它以相比早期版本更為自然、緊密和完全的方式地加入了現代物件導向的編程範式。反對者們有不同意見，雖然 VB6 對物件模型支援有缺點，但是二次開發升級到 VB.NET 的成本比升級後的收益要高得多。而開發軟體發布網際網路版本的獨立程式設計師也對 VB.NET 的 RunTime 尺寸過大不滿。

針對開發者的不滿，微軟主要做了如下努力：使新的開發更容易啟動，而把已經開發的 VB6 代碼升級到 VB.NET。例子主要包括：完成 VB6 中的常見任務如預覽列印；整合 VB6 和 VB.NET 解決方案（dubbed VB Fusion），從 VB6 代碼轉換到 VB.NET。

微軟在後續版本中復原了一些過激的更改，並且吸取了經驗。在以後版本中，語法的更改變得更加謹慎。

### 2003 年 Visual Basic .NET 2003（VB 7.0）

Visual Basic .NET 2003（VB 7.0）和.NET Framework 1.1 一起發布。新功能包括對.NET Compact Framework 的支援和更好的 VB 升遷精靈。並改進了執行狀況，IDE 穩定性（尤其是後台編譯器），以及執行時 RunTime 穩定性。另外，VB.NET 2003 還有一個學院版 Visual Studio .NET 2003 Academic Edition（VS03AE），它是分發給各國某些學者免費使用的版本。

### 2005 年 Visual Basic 2005（VB 8.0）

Visual Basic 2005（VB 8.0）是 VB.Net 的重大轉變，微軟決意在其軟體名稱中去掉了.NET 部份。在 VB2005 中，微軟增加了許多新功能，以參照 VB 對於初學者來說的一些優點：

主要的變動：

* 不再支援「Edit and Continue」 - 早期 Visual Basic 可以在除錯時修改代碼並且不經重新編譯地執行。Visual Basic 2005 去掉了這個功能；
* 設計時錶達式求值；
* 提供 My 偽命名空間，包含了不需大量編碼而存取特定.NET Framework 功能的簡單方式；提供了改進的 VB 到 VB.NET 轉換精靈；Using 語法，簡化了需要部署 pattern to free resources 的物件的使用；My 編碼，可隱藏由 VB.NET IDE 寫的模板代碼；資料來源繫結，簡化了資料庫 C/S 開發。上述功能（尤其是 My）增強了 VB.Net 成為快速開發應用平台的可能，並與 C# 進一步區別開來。Visual Basic 2005 通過增加新功能而減小了和其它所謂更強大的.NET 語言的差距。
* 增加了.NET 2.0 語言功能包括：泛型（generics）和 Partial 類（在一個檔案里定義一個類的某部份然後在另外的檔案里添加更多的定義，這個方法在整合使用者書寫的代碼和系統自動生成的代碼時尤其有用）；
* XML 注釋，可以被 NDoc 等工具處理而自動生成文件；
* 運算子多載；
* 支援在其它語言中已經廣泛使用的 unsigned integer 資料類型；
* 支援在許多 C 衍生程式語言已提供的複合運算子如："+=", "-="；
* IsNot 專利：If Not X Is Y 表達式被轉換成 If X IsNot Y。當微軟為 IsNot 申請專利時招致了惡名（尤其來自 Real 公司）；
* Visual Basic 2005 Express：作為 VS 產品線上的一部份，VB2005 Express 是專為業餘愛好者和新手客製化的免費的 VS Express 系列的一員。Express 版本目的定位在幫助人們學習一種語言，所以他們有和標準版一致的使用者介面，只是少了一些進階功能。另外，VS Express 版包括了 VB6.0 轉換器，提供了從 VB 老版本升級的可行方法。

### 2008 年 Visual Basic 2008（VB 9.0）

Visual Basic 2008（VB 9.0）於 2007 年 11 月 9 日與 Microsoft .NET Framework 3.5 一起發布。

在 VB2008 中，微軟增加了許多功能，包括：

* IIF 函式
* 匿名類型
* 支援 LINQ
* Lambda 表達式
* XML 資料結構
* 類介面

### 2010 年 Visual Basic 2010（VB 10.0）

Visual Basic 2010 於 2010 年 4 月發布。

### 2012 年 Visual Basic 2012（VB 11.0）

### 2013 年 Visual Basic 2013（VB 12.0）

### 2015 年 Visual Basic 2015（VB 14.0）

Visual Basic 2015（VB 14.0）於 2015 年 7 月 20 日發佈。

### 2017 年 Visual Basic 2017（VB 15.0）

### 2019 年 Visual Basic 2019（VB 16.0）

### 2022 年 Visual Basic 2022（VB 17.0）

2022 年 9 月 13 日 - Visual Studio 2022 17.0.14 版 NewReleaseIcon

2022 年 8 月 9 日 - Visual Studio 2022 17.0.13 版

2022 年 7 月 12 日 - Visual Studio 2022 17.0.12 版

2022 年 6 月 14 日 - Visual Studio 2022 17.0.11 版

2022 年 5 月 10 日 - Visual Studio 2022 17.0.10 版

2022 年 4 月 19 日 - Visual Studio 2022 17.0.9 版

2022 年 4 月 12 日 - Visual Studio 2022 17.0.8 版

2022 年 3 月 8 日 - Visual Studio 2022 17.0.7 版

2022 年 2 月 8 日 - Visual Studio 2022 17.0.6 版

2022 年 1 月 13 日 - Visual Studio 2022 17.0.5 版

2021 年 12 月 16 日 - Visual Studio 2022 17.0.4 版

2021 年 12 月 14 日 - Visual Studio 2022 17.0.3 版

2021 年 11 月 30 日 - Visual Studio 2022 17.0.2 版

2021 年 11 月 16 日 - Visual Studio 2022 17.0.1 版

2021 年 11 月 8 日 - Visual Studio 2022 17.0.0 版

## 參考資料

## 參見

* C#
* Visual Basic
* Visual Studio

## 外部連結

### 官方網站

* （英文）Microsoft's VB.NET （頁面存檔備份，存於網際網路檔案館）
* （英文）Visual Basic 2005 Express Edition
* （英文）VBRun 網站 （頁面存檔備份，存於網際網路檔案館）
* （繁體中文）Visual Studio Express（頁面存檔備份，存於網際網路檔案館）
* （繁體中文）Visual Studio Express Visual BASIC 下載 （頁面存檔備份，存於網際網路檔案館）

### 教程

* 使用 My 開發 （頁面存檔備份，存於網際網路檔案館）
* 通過 My 命名空間存取.NET Framework 和專案

### 其他

* SharpDevelop （頁面存檔備份，存於網際網路檔案館） - VB.NET 的一個免費 IDE
* VB.NET 的 MONO 應用
* VB.NET Knowledge Base（頁面存檔備份，存於網際網路檔案館） - VB.NET 知識庫 / 程式設計俱樂部