Visual Basic .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關鍵字。

**數組**
Dim arr(upperLimit) As dataType = new dataType(upperLimit) {initialValues} '聲明數組
arr(index) = value   '使用數組
數組的下標開始自0，這遵從了.NET的標準。如果不指定數組的下標上界，則為動態數組，其長度可以動態調整。

**結構控制語句**

**分支語句**
If語句
If 條件 Then
語句
ElseIf 條件 Then
語句
Else
語句
End If
*Switch語句
Select Case Variable
Case Value1
Statements
Case Value2
Statements
Case Value3
Statements
...
Case Else
Statements
End Select

**循環語句**
包括下述幾種：
*For...Next循環
For varName = 初值 To 終值 Step 步長
循環體語句
Next varName
*Do循環
Do Until} condition
statements
Exit Do
Loop
或
Do
statements
Exit Do
statements
Loop Until} condition
*While循環
While condition
statements
Exit While
statemenst
End While
*For Each...Next循環
For Each element in group
statements
Next element

**Yield語句**
實現迭代器遍歷一個序列，每次獲取一個返回值。迭代器可以作為一個方法或屬性的get訪問器，其中的Yield 語句返回迭代器的返回值，並記住當前執行的位置。下次再調用迭代器，從該執行位置恢復執行，直至迭代器代碼執行完或者遇到Exit Function或Return語句。編譯器把迭代器作為一個狀態機的類。   
Sub Main()
Dim days As New DaysOfTheWeek()
For Each day As String In days
Console.Write(day & " ")
Next 
' Output: Sun Mon Tue Wed Thu Fri Sat
Console.ReadKey()
End Sub 
Private Class DaysOfTheWeek
Implements IEnumerable
Public days =
New String() {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}
Public Iterator Function GetEnumerator() As IEnumerator _
Implements IEnumerable.GetEnumerator
' Yield each day of the week. 
For i As Integer = 0 To days.Length - 1
Yield days(i)
Next 
End Function 
End Class

**物件導向**
物件導向時，類的聲明範例：
Public Class className Inherits bassClassName
Public varName As Integer '資料成員
Public ReadOnly/WriteOnly Property propertyName() As Integer '屬性
Public Get
Return m_var
End Get
Public Set(ByVal value As Integer) 
m_var=value
End  Set
End Property
Public Sub subName(ByVal param1 As Integer) '方法
End Sub
Public Function funcName(ByVal param2 As Integer ) As Integer '函數
Return 101
End Function
atrributive_listaccessibilibyShadowsEvent eventName(Parameter) Implements interfaces.event '事件
Public Sub new(Parameter) '類的構造子(constructor)，可以有多個（即可以重載）
End Sub
End Class
上述示例中的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）**
介面是一類特殊的抽象類，不能包括可執行代碼與類的資料成員的聲明：
Interface interfaceName
Event eventName(param)
Property ReadOnly/WriteOnly propertyName As typeName
Function funcName(param) As returnTypeName
End Interface
介面中這些成員都強制是Public可存取性。
實現一個介面，使用Implements關鍵字：
Public Function GetEnumerator() As IEnumerator _
Implements IEnumerable.GetEnumerator

**多型（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關鍵字。例如：
Public Class Person
Public Property age As Integer
Public Property Name As String
End Class
Dim personList As New List(Of Person) From {
New Person With {.Name = "Qiang", .age = 24},
New Person With {.Name = "Wei", .age = 42}
}

**匿名類型**
例如：
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
Public Function funcName(ByVal ins As className) As String
'Do something
End Function

**異常處理**
Try
' write the condition here
Catch ex As Exception When condition
' Handle Exception when a specific condition is true
Catch ex As Exception
' Handle Exception
Finally
' Cleanup, close connections etc
' NB this code is always executed regardless of if an Exception was raised or not!
End Try

**LINQ**
From element  As type  In collection , element2  As type2  In collection2 , ...   Where 表達式

**例子（Hello World）**
這裡給出了一個Hello World的例子。通過它們您可以更好地理解Visual Basic的特性。（此源代碼運行於命令行下）
Module Mdl_Main
Sub Main()
Console.WriteLine("Hello World")
End Sub
End Module
這個程序能輸出Hello World。
Module Mdl_Main
第一行是模塊定義，命名空間的定義一般可以省略。VB.NET中，所有函數，過程與變量的聲明都必須在模塊或者類的內部，而不能直接存在於命名空間內部。
Sub Main()
第二行定義了名為Main的過程。一般來說，“Sub Main()”是程序的入口點。
Console.WriteLine("Hello World")
第三行輸出“Hello World”。
End Sub
第四行結束了過程Main的定義。
End Module
第五行結束了模塊Mdl_Main的定義。

**與舊版VB比較**
與舊版VB（VB 6.0及以前）相比較，VB.NET明顯受到了.Net Framework中其他語言思想的影響。與舊版VB相比，VB.NET更加嚴格而不失靈活。- Long類型與Integer類型的長度分別倍增，達到了64位和32位。- 事件的處理過程不再依賴於名稱，而是通過Handle子句進行靜態綁定或者在運行時進行動態綁定。例如處理按鈕控件Button1的Click事件：
Visual Basic 6：（注意此過程的名稱不可改變）
Private Sub Button1_Click()
'Work to do
End Sub
VB.NET：（注意此過程的名稱無關緊要）
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
'Work to do
End Sub- 很多原有的實現特殊功能的語句被相應定義好的函數替代。這減少了關鍵字的使用（如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：
Namespace N
	'Comment
	Module M
		Public Function GetSum(arr() As Integer) As Integer
			Dim Sum = 0 'Auto Type Infer
			Dim i As Integer
			
			For Each i In arr
				Sum += i
			Next
			
			Return Sum
		End Function
	End Module
	
	Class C
		Private v As Integer
	
		Public Function F() As Integer
			Return v * v
		End Function
		
		Public Sub S(value As Integer)
			Me.v = value
		End Sub
		
		Public Sub New() 'Constructor
			Me.v = 0
		End Sub
	End Class
End Namespace- C#：
namespace N
{
	//Comment
	static class M
	{
		int GetSum(int arr)
		{
			var Sum = 0;
			int i;
			
			foreach(i in arr)
			{
				Sum += i;
			}
			
			return Sum;
		}
	};
	
	class C
	{
	private:
		int v;
	public:
		int F()
		{
			return v * v;
		}
		
		void S(int value)
		{
			this.v = value;
		}
		
		C() //Constructor
		{
			this.v = 0;
		}
	};
}
VB.NET與C#同為.Net Framework的兩大主力程序設計語言，儘管有著各種各樣的不同，兩者最終都編譯為MSIL並由CLR運行。兩者功能基本一致，並可以在.Net Framework框架下方便地互相調用與協同開發。關於兩者的優劣一直見仁見智。

**調用C語言函數的規範**
C語言編寫的DLL文件，VB在調用時，需要注意：對於C語言的數組指針，在VB中調用時應將數組的首元素傳遞給DLL。不能直接傳遞數組名,因為如果傳遞數組名,VB實際會傳一個複雜的結構類型給DLL。C函數無法確定數組大小，通常用另一個參數指出數組的大小。
Public Sub test(ByVal param As Integer, ByRef OK As Integer)
End Sub
'下述方法只能使用_stdcall調用約定：
Public Declare Function test1 Lib "D:\PackingDLL.dll" Alias "_test@4" (ByVal param As Integer) As Integer

**歷史**

**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 date=20210330195301 - Visual Basic 2005 Express Edition- VBRun網站 date=20080828201147  -  Visual Studio Expressdate=20070812203722 -  Visual Studio Express Visual BASIC下載 date=20220323060949 

**教程**
 使用My開發 date=20160210175233 - 通過My命名空間訪問.NET Framework和項目

**其他**
 SharpDevelop date=20191012035438  - VB.NET的一個免費IDE- VB.NET的MONO應用- VB.NET Knowledge Basedate=20090424015209  - VB.NET知識庫 / 程式設計俱樂部