C＃與Visual Basic .NET的比較

C#和VB.NET是微軟公司開發的.NET框架中，兩種面向對象的程式語言，分別衍生自C++語言及Visual Basic，因此在語法，註解方式都有許多的差異。

## 語言歷史

C#和VB.NET各自有其不同的歷史，在語法上也有很大的差異。C#語法的基礎是衍生自1970年代丹尼斯·里奇在貝爾實驗室（AT&T）發展的C語言，其中也包括了完全物件導向的C++，許多Java語言語法的基礎也是來自C++語言，這也是C#和Java有許多相近之處的原因。

VB.NET是來自1960年代的BASIC語言，是「Beginner's All-purpose Symbolic Instruction Code」的縮寫，一開始BASIC在學校中教授，而且如它的名字所述的，被視為是一個基礎的程式語言。1970年代微電腦的製造商將BASIC用來做電腦系統的程式語言，以及有簡單輸入輸出控制的半作業系統。1980年代微軟也開始使用將一此語言，1990年代發展為Visual basic，用在window系統的快速應用程式開發，Visual basic打敗了當時像PowerBuilder等快速應用程式開發工具。雖然Visual Basic如此的成功，但在2000年代初期微軟提出.NET框架及對應的Visual Studio開發平台，而Visual Basic也在第六版（VB6）畫下句點。

## 語言比較

雖然C#和VB.NET在語法上有相當的不同，但因為都是微軟開發的.NET框架下的程式語言，而且是由同一個開發團隊進行開發、管理及維護，因此會有不少的共通點。C#和VB.NET會編譯為同一種中介語言，在同一種.NET框架下的執行期函式庫下執行。C#和VB.NET在語言結構上有一些差異，差異主要都是語法上的差異，但不要使用微軟提供，方便和VB6轉換的相容性函式庫，幾乎每一個VB.NET中的指令都有對應的C#的指令，反之亦然。為了延伸其機能，兩種語言也參考同一個.NET框架下的基礎類別。因此大多數用其中一個語言寫的程式可以用語法轉換程式轉換為另一種語言，只有少數例外，而已有許多開源軟體及商業軟體有這類的功能。

### 語言特性

從技術角度來看，C＃和VB.NET之間的大部分差異都是語法糖。也就是說，大多數特性都存在於兩種語言，但有些任務在一種語言中比另一種語言更容易完成。

#### 存在於Visual Basic .NET但不存在於C#的特性

- 可以使用`WithEvents`結構聲明變量。此結構令程式設計師可以從「類名」下拉列表中選擇一個對象，然後從「聲明」下拉列表中選擇一個方法以自動插入方法簽名。
- 自動連接事件。VB.NET支持事件的`Handles`語法，它將事件處理程序連接到對象變量而不是對象。
- 使用`RaiseEvent`關鍵字引發事件，IDE在此關鍵字後會顯示可用的事件列表。`RaiseEvent`隱式檢查事件處理程序是否為Nothing。（在C＃中引發事件在語法上與調用過程完全相同，並且需要額外的代碼行來檢查有線事件處理程序）
- 事件代理被隱式聲明。
- 在`With ... End With`結構內，點操作符前可不寫出對象名。
- XML文本
- date文本常量，如`#12/31/2000#`
- `Module`語句（雖然C#的靜態類更容易理解，但靜態類里每個成員都必須顯示聲明為`static`。）
- 當前文件導入模塊後，該模塊的成員可以無需限定符進行訪問。
- `My`命名空間
- COM組件和互操作性更強，因為對象類型是運行時綁定的。C# 4.0的`dynamic`關鍵字提供了相同的便利。
- 可以在項目級別導入命名空間，這樣一來該項目的每個文件都可訪問該命名空間。
- 使用`#Const`指令定義條件編譯器常量。`#Const`常量一般在`#If`語句中使用。
- 屬性可以攜帶參數。
- 屬性可以直接按引用（`ByRef`）傳入方法。在C#里屬性必須先賦值給局部變量，再傳入。
- 接口裡可定義枚舉。
- `Case`語句可接不等式，如`Select x: Case Is >= 3`。(在C#里必須用`if ... else`實現。)
- 子類若有與父類同名的方法，則子類方法必須被`Overloads`關鍵字修飾。(C＃中缺少此關鍵字可能會導致意外重載)
- `Like`運算符支持模式比較。（C#只能訪問`Microsoft.VisualBasic.CompilerServices.LikeOperator.LikeString`方法)
- `Return`語句可省略。也可向當前方法賦值來設置返回值。
- Visual basic有不少內置常量，如`vbCrLf`、`vbTab`。
- 沒有用於修飾參數的`out`關鍵字。
- `MyClass`關鍵字的行為類似於引用最初實現的類的當前實例。`MyClass`類似於`Me`，但是對它的所有方法調用都被視為方法被NotOverridable修飾。
- `MyBase.New`用來調用父類的構造函數。
- 局部變量自動初始化。
- 方法內的靜態局部變量在方法調用多次時可保持原來的值。
- `End`語句直接終止程序。
- 可對Lambda表達式推斷類型，如`Dim x = Function(n As Integer) n + 1`
- 成員名可以與其所在的類型名相同。

#### 存在於C#但不存在於Visual Basic .NET的特性

- 多行注釋。
- 靜態類。
- C#和VB都可以在項目屬性里開啟或禁用溢出檢查，但C#提供`checked`、`unchecked`關鍵字進行精細控制。
- for語句可以有多個條件，如`for(int i = 0; i < 10 && somethingTrue; i++)`。
- 屬性的getter和setter可以實現不同的接口。VB里必須定義兩個屬性。
- 隱式接口實現。
- null條件運算符`??`返回第一個非null值（如`null ?? null ?? 1`返回`1`）。
- 可在`unsafe`環境使用指針
- 條件運算符`?`: `someThingTrueOrFalse ? whenTrue() : whenFalse();`

#### 存在於Visual Basic .NET但無法應用到C#的特性

- 轉換布爾值True到Integer可能會產生-1或1，具體取決於所使用的轉換。
- 變量賦值和比較使用相同的符號：`=`。C#用不同的符號：`==`和`=`，這允許在條件語句中先賦值，再比較。
- VB.NET標識符不區分大小寫。
- 當為具有不同數據類型的變量賦值（並且`Option Strict`未打開時），VB.NET將儘可能強制轉換該值。這種自動強制轉換有時會導致意想不到的結果，比如

```vb
Dim i As Integer = "1" '编译器插入一个从String到Integer的转换方法
Dim j As String = 1 '编译器插入一个从Integer到String的转换方法
If i = j Then '编译器插入一个从String到double的转换方法
    MsgBox("Avoid using, but this message will appear!")
End If
```

為了向後兼容，`Option Strict`的默認值是關閉，但微軟建議將其開啟

- 內置函數`Val()`的參數可以是null。
- 有大量內置的類型轉換函數：CInt, CStr, CByte, CDbl, CBool, CDate, CLng, CCur, CObj。

#### 存在於C#但無法應用到Visual Basic .NET的特性

- C＃標識符區分大小寫。
- 可將同一值賦給多個變量：`a=b=c`。

## 兩種語言的HelloWorld

以下是兩種語言的HelloWorld：

VB.NET

```vbnet
Imports System

Module HelloWorldApp
    ' VB.NET Console 主程序
    Sub Main()
        ' 輸出 Hello World! 至 Console
        Console.WriteLine("Hello World!")
        ' ReadKey 用來暫停避免直接關閉 Console 視窗
        Console.ReadKey()
    End Sub
End Module
```

C#

```csharp
using System;

namespace HelloWorldApp
{
    class Program
    {
        // C# Console 主程序
        static void Main(string[] args)
        {
            // 輸出 Hello World! 至 Console
            Console.WriteLine("Hello World");
            // ReadKey 用來暫停避免直接關閉 Console 視窗
            Console.ReadKey();
        }
    }
}
```