本文譯自 http://www.mightywords.com/browse/details_bc05.jsp?privateLabel=true&sku=MW8NN0&etailerId=1063
Visual Basic.NET 是 Visual Basic--但不是你以前所熟悉的 Visual Basic
這表示每一個 VB6 的開發者要成為一個熟練的 Visual Basic.NET 將會有一段不算平滑的學習曲線。因為新的語法與觀念,以及 .NET 架構上的 Class 都需要去了解。這引發的一個疑問
”既然我無論如何都需要學一個新語言,哪我為何不學新的 C#”
在回答這個問題之前,讓我先提供 Visual Basic 與 C++ 程式設計師另外一個問題
”C# 是一個全新的語言,既然要全新的 C# 那為何不學 VB.NET”
第一個問題其實潛藏了一個想法,當 VB6 的程式設計師問到”為何我不學習 C# 來取代 VB.NET”時,他實際代表的意義是:
”我可以用 VB 做很多不錯的程式設計,但 C++ 的程式設計師卻仍然瞧不起我。他們賺更多的錢,他們都說 VB 是玩具語言 -- VB 不如 C++ 的速度與能力。他們一再強調 C++ 可以做到但 VB 做不到的部分。現在,所有的 C++ 程式設計師都被告知 C# 是 .NET 環境中最好的語言,而 C# 也的確非常像 C++ 或 Java。既然我在學 VB.NET 時需要花費很多心力,那為何不將這些努力放在 C# 上,讓我今後可以成為真正的程式設計師,可以含他們一樣賺更多的錢。”
在討論真正的主題時,我們需要先釐清以下的觀念:
VB.NET 是完全與 CLS ( common language spec)相容,也就是說它可以完全發揮 .NET 執行環境的能力。
C# 提供少數在 VB.NET 無法辦到的特色,但這些特色對絕大多數的 VB 程式設計師來說是沒有用的。
兩個語言都與 CLS 相容,也就是說你在極少數的狀況下需要 C# 的特色,也可以在 VB.NET 專案中利用這些 C# 程式碼。
如果你接受這些觀念,則很明顯的 VB 程式設計師應該不再在 C++ 或 C# 的程式設計師的面前感到自卑。
VB.NET 與 C# 一樣好,甚至在某些方面更好
你應該考慮真正符合經濟效益的語言
符合經濟效益?
是的,如果兩個語言如此的相似,那決定的因子應該是經濟效益。
在評估語言時的經濟效益因子
當一個專業的軟體開發人員你應該尋找最經濟的軟體開發解決方案。在這個前提下,你應該考慮軟體專案整個開發週期的成本,也就是在你心中應該有以下的考量因素
學習需要時間且花成本
在同一時間使用多種語言需要心智上的位移,讓部分的程式設計師會降低開發效率(困擾多於成本的考量)
在開發時期撰寫正確的程式碼比在其它任何時期校正程式碼﹔在成本上都比較便宜
長遠來說容易讀以及了解的程式碼在除錯與維護的成本上較便宜
讓我們就以這幾點來討論
學習需要時間且花成本
基本上我假定 VB 的程式設計師學 VB.NET,C++ 的程式設計師學 C# 比較快。VB 的程式設計師基本上在 VB.NET 只要注意一些細節上的差異,如整數變成 32 位元,參數傳遞預設是 ByVal 而不再是 ByRef 等等。但我相信 VB6 的程式設計師熟悉 VB.NET 的語法會快過 C# 的語法。
在同一時間使用多種語言需要心智上的位移
以我個人的經驗我常常在 VB 寫 C++ 程式碼,在 C++ 寫 VB 的程式碼。
在開發時期撰寫正確的程式碼比在其它任何時期校正程式碼﹔在成本上都比較便宜
哪一個語言可以讓你較容易完成無錯誤的程式碼?哪一個語言在撰寫與編譯時期可以抓出最多的錯誤。你將會發現 VB.NET 和 C# 在這方面是非常相似的。
長遠來說容易讀以及了解的程式碼在除錯與維護的成本上較便宜
在後面的文章將會更進一步說明此點
讓我們開始比較
在以下的文章我們將逐項比較 VB.NET 和 C#。需要強調的是這裡做的是兩個語言差異上的比較,而不是表列兩個語言的特色,所以兩個語言共有的特色或不需比較的,在本文中不會出現。
資料和變數
VB.NET 支援所有的 CLS 標準資料型態,C# 增加支援無正負號的資料型態。下表列出兩個語言的基礎型態以及是否與 CLS 相容
VB.NET
C#
與 CLS 相容
Object
object
Y
String
string
Y
sbyte
N
Short
short
Y
Integer
int
Y
Long
long
Y
Byte
byte
Y
ushort
N
uint
N
ulong
N
Single
float
Y
Double
double
Y
Boolean
bool
Y
Char
char
Y
Decimal
decimal
Y
第一眼看起來 C# 贏得這一項,但真正重要的是贏得這一項應該考慮與 CLS 相容。
當你的元件與 CLS 相容時,就可以百分之百保證任何其他與 CLS 相容的語言都可以存取元件的方法、屬性都沒有問題。也保證其他的 CLS 相容語言都可以實做你所定義的介面,繼承你的 Classes。也同時保證其他與 CLS 相容的工具可以使用這個元件。
換句話說,CLS 相容是 .NET 的基礎。C# 可以使用無符號的變數,但應該在應用程式的內部使用。你應該在定義 structures、方法、和屬性等等會出現在 assembly 的內容時避免使用.
VB 的程式設計師會希望使用無符號型態是因為需要呼叫 Win32 API,但 .NET 大幅降低了 Win32 API 的重要性,且透過 .NET 的 interop system 會自動 marshalling 有符號與無符號之間的資料。
判決:若不考慮與 CLS 相容,C# 在這個主題上獲勝,反之則 VB.NET 獲勝,因為除了違反 CLS 的相容性外,使用不相容的無符號變數會有潛在資料轉換的錯誤,以及因為增加了複雜性而以長遠來看會提升維護成本。
Shift 運算子
C# 提供與 C 和 C++ 相似的 left-shift 和 right-shift(<< 和 >>)運算子。對 VB 程式程式設計師來說這是公認少用的需要,因為他們比較專注商業應用程式,但我個人希望微軟將它們加到 VB.NET
判決:C++ 在這種少用的運算子上獲勝
Operator Overloading
C# 支援 Operator Overloading,讓 +、-、* 等等運算子可以在定義新的資料型態後,重新定義運算子對這些型態的意義。
Operator Overloading 往往被程式設計師高估了。有一個傾向是一些 C++ 的程式設計師會定義一些 class 使用的 overloaded 運算子,但卻沒有任何意義。你應該在很直觀的情境下使用 overloaded 運算子,否則要開發者去記憶某些運算子的特有意義是強人所難。當然,為複數 overloading "+" 是來做向量加法是一個不錯的例子。
VB.NET(至少 Beta1)並不支援 Operator Overloading。
當與 CLS 相容的語言如 VB.NET 嘗試要使用有 overloaded operators 的 Class 時會發生什麼狀況呢?在 VB.NET 這個運算子是不能用的,但你可以利用 overloaded 函數如 op_Addition 或 op_Subtraction 來做同樣的事。
大部分的 VB 程式設計師都不需要 operator overloading。C# 程式設計師若要建立其他語言使用的 assemblies 也要避免使用 operator overloading,取而代之的是利用簡單易懂的函數。
判決:C# 贏得這個主題,尤其對於某些在科學領域的程式設計師尤其重要,但這個特點對 VB 程式設計師來說毫不重要
變數初始化和 local scoping
VB.NET 自動將所有的變數初始化成 0 或 nothing。C# 在你未初始化變數之前不准你用該變數。在大多數的狀況下這不成問題,但因為 VB.NET 只有在建立時初始化變數,所以會有一些微小的狀況。以下列 C# 程式而言
int x;
for(x=1;x<3;x++)
{
int i=0;
Console.WriteLine(i);
i++;
}
會連續出現兩個 0,但若以同樣的 VB.NET
Dim x As Integer
For x = 1 To 2
Dim i As Integer
Console.WriteLine(i)
i += 1
Next
則會出現 0 和 1,當然若你以下列的語法
Dim i As Integer = 0
會出現兩個 0
判決:C# 小贏
型別轉換支援(Conversion Support)
VB.NET 不支援從一個結構型別定義自訂型別轉換到另外一個。取而代之的是要以特別命名的方法來完成這個動作。以下的程式碼表列出你可以
public struct SomeStruct
{
public int x;
public static explicit operator string(SomeStruct s)
{
//故意讓 (string) 的結果不同,做自訂轉換的動作
return s.x.ToString()+10.ToString();
}
public override string ToString()
{
return((string)this);
}
}
public class Class1
{
public static int Main(string[] args)
{
string ResultString;
SomeStruct s;
s.x=5;
ResultString=(string)s;
Console.WriteLine(ResultString);
Console.WriteLine(s.ToString());
return 0;
}
}
為何仍然要 Override ToString 方法?因為這種自訂型別轉換並不與 CLS 相容,CLS 允許自訂型別轉換,但需要以正確的 ToXXX 或 FromXXX 的格式建立方法,讓不支援 C# 格式的其他語言可以執行轉換。
判決:在不考慮與 CLS 相容下,C# 小贏。我希望微軟會將這項功能加入到 VB.NET
函數語法
VB.NET 和 C# 在函數呼叫的方法上有許多不同
函數回傳值
VB.NET 維持原先若函數不提供回傳值便自行回傳 0 或 Nothing(若回傳字串,則等於 Null 字串)。C# 要求每一個可以離開的程式執行路徑一定要有明確的回傳語法。因此 C# 編譯器在你沒有提供需要的回傳值時會警告你。
判決:C# 提供了明顯的好處在函數編譯的第一時間幫忙解決潛在的回傳值錯誤
選擇性參數(Optional parameters)
C# 不提供函數選擇性參數,但仍可以利用會獲得相同結果的 overloading,所以不算大輸。
判決:VB.NET 提供以一個函數做到多個函數才能做的 overloading 而贏得這一項
模組(Modules)和靜態(Static)成員(Members)
C# 所有的程式碼都要存放在 Class,VB.NET 持續支援標準模組。定義在標準模組的函數和變數會在 assembly 中以 global 的方式呈現。標準模組是與 CLS 相容的,C# 無法定義這一點。
C# 和 VB.NET 都在 Class 支援靜態方法、屬性和 fields(在 VB.NET 稱為 Shared)。它們在使用時不需真正建立物件,例如
class AClass
{
public static void StaticMethod()
{
Console.WriteLine("不需要建立物件就可以呼叫");
}
}
則呼叫 StaticMethod 只需要
AClass.StaticMethod();
在 C# 呼叫靜態方法只能透過 type 名稱,在 VB.NET 則同時可以利用 type 名稱或是物件的 instance 來呼叫,範例如下
Class AClass
Public Shared Sub ShareMethod()
Console.WriteLine("可以不建立物件來呼叫函數")
End Sub
End Class
可以透過以下兩種的程式碼使用
AClass.ShareMethod()
Dim a As New AClass()
a.ShareMethod()
這變成是哲理性的考量了,C# 提供了紀律:如果你想要建立與物件無關但以函數組成的函式庫(library),你必須建立 Class 來實際地將函數群組在一起,雖然你從來都不會為該 type 建立物件。由於所有的靜態成員仍需以 type 名稱來存取,會強制要求程式設計師明確知道該成員的共享特色。
VB.NET 提供了開發人員更大的彈性。你可以為一般功能函數建立傳統的標準模組,它可以在不指定任何 class 或模組名稱下直接使用。你可以存取物件的 instance 的 shared 成員,但這有讓 shared 物件與 instance 物件混淆的危險。
判決:我會為標準模組判 VB.NET 小贏,但仍強調這比較是個人偏見而非令人信服的邏輯判讀。我會在少有狀況下﹔程式設計師在 shared 和非 shared 成員混淆時,判給 C# 要求一定要透過 class 名稱來使用靜態成員的方式小贏。
Switch 和 Select Case 語法
在 C# 的 switch 語法讓你以某個值或語法跳到一個程式區塊。每一個區塊與一個常數值連結在一起。你可以使用多個常數值與 case 語法建立如下的程式碼
switch(i)
{
case 4:
case 5:
break;
case 6:
case 7:
break;
default:
break;
}
VB 則讓你可以組合常數或更複雜的語法,如下
Select Case i
Case 4, 5
Case 6 To 9
Case Else
End Select
不只如此,VB.NET 也讓你可以在 Select Case 語法中如同使用常數一般使用變數
判決:VB.NET 在這方面明顯獲勝,雖然 C# 簡單的語法對讓撰寫有效率的程式碼有稍稍的幫助。
物件語法
以下是在 VB.NET 和 C# 間使用物件上語法相異的討論。這裡沒有做各項的評分,僅提供一個整體的判決。
傳值或傳址呼叫
所有的 VB.NET 參數都要明確地利用 ByVal 和 ByRef 宣告,C# 的參數都是傳值,除非以 ref 關鍵字宣告。
Overloads
如果在 C# 宣告兩個相同方法名稱但不同的組成參數就自動是 overloads 的函數方式,VB.NET 需要明確地使用 Overloads 關鍵字。
呼叫基礎建構子(Base Constructors)
在 C# 要呼叫基礎建構子的語法如下
public AClass():base()
{
}
而 VB.NET 的語法如下
Public Sub New()
MyBase.New()
End Sub
Virtual/Overridable 方法
C# 使用 Virtual 關鍵來宣告就算是參照到基礎 Class,但仍是呼叫到正確衍生類別的方法。
VB.NET 使用 Overridable 關鍵字來宣告 virtual 函數,並需要使用 Overrides 關鍵字來宣告衍生的函數,以 override 基礎 Class 的函數。
Abstract/MustInherit 方法
C# 用關鍵字 abstract 關鍵字來標示需要藉由衍生 Class 來實做的方法,VB.NET 使用 MustInherit 關鍵字來做同樣的標示(同時使用在 Class 和方法)。
Sealed/NoInheritable Classes
C# 用關鍵字 Sealed 來標示不可以被繼承的 Classs,VB.NET 以 NotInheritable 關鍵字來做相同的事。
其他的屬性
C# 使用 internal 關鍵字來定義 class 或成員的 scope 是在 assembly 之內,而 VB.NET 以 Friend 做相同的宣告。
Shadowing
VB.NET 當你在衍生的 class 宣告了與基礎 class 相同的成員名稱會提出警告,以強迫你 override 或是利用 Shadows 關鍵字(譯者註:Shadows 關鍵字在 VB.NET Beta1 似乎尚未支援)來標示當參照到衍生 Class 時,使用衍生 class 的成員而非基礎 class 的成員,而參照基礎 class 的 instance 時,使用基礎 class 的方法。C# 使用 new 關鍵字來隱藏從基礎 Class 繼承來的方法,並用 override 關鍵字來 override virtual 或 abstract 基礎 class 的方法。
介面(Interface)和繼承(Inheritance)
讓我們看一下 C# 和 VB.NET 如何實做 class 繼承和介面繼承。在這個範例中我們定義了介面 Iint,以及基礎 Class 稱為 AClass,以及衍生 AClass 的 BClass,並實做 Iint 介面。
在 C# 程式碼如下
namespace ConsoleApplication2
{
using System;
interface Iint
{
int x();
}
public class AClass
{
public int x()
{
Console.WriteLine("在基礎 Class 的 x");
return(0);
}
}
public class BClass:AClass,Iint
{
int Iint.x()
{
Console.WriteLine("在介面上的 x");
return(0);
}
}
class Class1
{
static void Main(string[] args)
{
BClass c=new BClass();
Iint i=c;
c.x();
i.x();
Console.ReadLine();
}
}
}
C# 不需要你明確地定義哪個函數實做哪個介面,也就是以下的程式碼
int Iint.x()
換成
new public int x()
則認為這個 x() 函數不僅可以直接存取,也是實做介面的 x() 方法。
而 VB.NET 的對應語法如下
Imports System.Console
Interface Iint
Function x() As Integer
End Interface
Public Class AClass
Function x() As Integer
Console.WriteLine("在基礎 Class 的 x")
Return 0
End Function
End Class
Public Class BClass
Inherits AClass
Implements Iint
Private Function IintX() As Integer Implements Iint.x
Console.WriteLine("在介面上的 x")
End Function
End Class
Module Module1
Sub Main()
Dim b As New BClass()
Dim i As Iint
i = b
b.x()
i.x()
Console.ReadLine()
End Sub
End Module
VB.NET 需要使用 Implements 關鍵字來明確定義哪個方法實做哪個介面方法。事實上,你可以一個方法來實做多個不同的介面方法,如果介面定義如下:
Interface Iint
Function x() As Integer
Function y() As Integer
End Interface
你可以一個方法實做這兩個,程式範例如下
Private Function IintX() As Integer Implements Iint.x, Iint.y
Console.WriteLine("在介面上的 x")
End Function
當你有兩個相似的介面並共享許多相同的方法,這個實做方式就很有用。
對物件語法的判決
程式語法對程式設計師來說是信仰問題,大家都比較喜歡自己熟悉的語法,其實沒啥好評斷的。
從以上的描述中你也可以發現其實這兩的語言的差異性很小,兩者都有相似的功能。
但無論如何,我必須在物件語法上判 VB.NET 贏,就以以下繼承語法來看
public class BClass:AClass,Iint
與
Public Class BClass
Inherits AClass
Implements Iint
以及以下控制繼承的關鍵字
abstract,sealed,virtual,new
與
MustInherit,NotInheritable 與 Overridable,Overrides 和 Shadows
當一看到程式碼想要了解它在做啥事,特別是剛畢業的新程式設計師要接舊程式時,如欲他迅速上手並解決模糊不清的錯誤,或想增加新功能時,哪一種語法較容易理解?
Visual Basic.NET
雖然兩者差不多,但 VB.NET 贏得這一項。
事件(Events)
在 C# 你必須要完成很多的動作後才能定義事件,第一步你必須要宣告事件所需的 delegate type 如下
public delegate void ChangedEventHandler(object sender, EventArgs e);
這定義了事件的 signature(參數和參數型態)。 e 參數是繼承自 EventArgs class 的任意 class 以包含事件參數的各種欄位。
接著 Class 要定義一個該 delegate 型態的事件變數
public event ChangedEventHandler Changed;
要觸發這個事件,Class 呼叫
Changed(this,TheEventArguments);
要承接這個事件,使用者程式必須要定義一個與 delegate signature 相同的函數
private void ObjectChanged(object sender,EventArgs e)
{
Console.WriteLine(e.ToString);
}
並且需要連結這個函數與發出事件 delegate 的物件
a.Changed+=new ChangedEventHandler(ObjectChanged);
譯者註:整個架構如下
namespace ConsoleApplication2
{
using System;
public class EvtArg:System.EventArgs
{
public string strEvt;
public EvtArg(string strIn)
{
strEvt=strIn;
}
}
public delegate void ChangedEventHandler(object sender, EvtArg e);
public class AClass
{
public event ChangedEventHandler Changed;
public virtual int x()
{
Console.WriteLine("在基礎 Class 的 x 以 Changed 觸發事件");
Changed(this,new EvtArg("事件原因..."));
return(0);
}
}
class EvtHand
{
public void ObjectChanged(object sender,EvtArg e)
{
Console.WriteLine("ObjectChanged 處理事件:" + e.strEvt);
}
}
class Class1
{
static void Main(string[] args)
{
AClass a =new AClass();
EvtHand h=new EvtHand();
a.Changed+=new ChangedEventHandler(h.ObjectChanged);
a.x();
Console.ReadLine();
}
}
}
一剛開始這一定會造成困擾,就算使用一陣後仍不太能夠適應。
VB.NET 的程式設計師可以用完全相同的方式觸發事件,另外也可以使用與 VB6 相容的傳統方式觸發事件,在 Class 中可以定義事件如下
Event Changed()
你可以使用任何你想定義的事件 signature,一般會用 Sender,EventArgs 的技巧如下
Event Changed(Byval Sender As Object,ByVal e As EventArgs)
觸發事件可以透過 RaiseEvent 關鍵字
RaiseEvent Changed()
使用事件的物件可以宣告如下
Dim WithEvents b As BClass
並透過以下的方式將處理事件的方法和事件連結起來
Sub EventHandle() Handles b.Changed
End Sub
對於 VB6 來說 event 處理是一項改良,副函數可以從任何物件、任何函數名稱處理事件,並且事實上同一個函數可以處理多種事件。
判決:VB.NET 大勝。VB.NET 可以使用與 C# 一樣複雜的語法,也可以簡單的語法提供動態建立的屬性,以宣告事件的語法提供多種狀況下任何 signature 形式的事件。
VB 命令
想一下 VB6 與 C++ 的差異,C++ 是一種非常簡練的語言--它的關鍵字非常少。也就是說 C++ 程式設計師要靠大量的函式庫--不管是標準的 C runtime、標準的範本函式庫,或是撰寫 Windows 程式的 ATL 或 MFC class library。比起 VB6 的軟體開發人員而言,C++ 的程式設計師也需要對 Win32 API 有更多的了解。
VB 在歷史上真正的力量就在於將那些函數、class libraries 包裝成非常豐富的內建函數或關鍵字。
在 .NET 上,C# 程式設計師可以幾乎使用所有的 .NET framework classes,以及一些 class library 為包含的 Win32 API。VB.NET 當然也可以完全存取這些資源,但它仍然保留了原先內建,強固的關鍵字集合。
但在你以這個原因為主要考量決定採用 VB.NET 時,可以考慮以下的 C# 程式碼
String s="asdf";
Microsoft.VisualBasic.Strings.Mid((s,2,2));
這是什麼,在 C# 呼叫 Visual Basic 的函數?(譯者註:要測試這種做法,C# 要參照 Microsoft.VisualBasic)
是的,大部分 VB 內建的函數現在 .NET 環境下都屬於 Microsoft.VisualBasic namespace。因為它屬於 .NET framework 的一部份,且與 CLS 完全相容,所以這些功能可以被 C# 或是任何其他的語言使用。
當然,這並不表示完全相同,VB.NET 並不需要使用完整的 Namespace 和物件名稱來確認使用的方法。同事 VB.NET 可以執行一些聰明的動作,如利用 mid 函數來設定字串中的子字串
Dim s As String = "abcdef"
Console.WriteLine(Mid(s, 2, 2))
Mid(s, 2, 2) = "xx"
Console.WriteLine(s)
VB 程式設計師在以上的程式碼中不會覺得有啥奇怪,但這真是一個令人訝異的動作。因為在 .NET 中字串是永遠不變的(它們不可以被修改),但 VB.NET 讓整個動作看起來是在私地下建立一個新的字串,並賦予到傳進 mid 函數的字串變數。
判決:VB.NET 贏。從語言的角度看,這是小贏。因為其他的 .NET classes 可以所有在 Microsoft.VisualBasic 中的操作。但從經濟的角度上考量就算不是大贏,也贏得不小。因為 VB 的程式設計師已經熟悉這些 VB.NET 的命令,使用它們可以快速成為 .NET 的開發人員。這是一個短期的好處(因為就算 VB 程式設計師選擇了 C# 最終也會學到 .NET 中對等的功能),但畢竟它是一個好處。對於 C++ 在 .NET 要選擇何種開發語言,這個優點就毫無意義了(譯者註:因為 C++ 的程式設計師本來也不知道 VB 所提供的命令)。
其他不同的語法
我在這裡不討論 VB.NET 與 C# 基礎語法上的差異,用大括號"{}"還是 Begin...End,用分號還是換行,以 for(,,) 或 For...Next。這些都是語言特色,沒啥麼好比較的。一但你熟悉了一個語言,要在對應到另外一個語言的特色是很容易的。
判決:完全依個人喜好,在這裡不做判決。
效能
我不願意在 Beta 版本比較兩個語言的效能,但記住兩點
1.VB.NET 和 C# 都大量使用了 .NET Framework,它才是兩個語言效能上的主要考量。
2.兩個語言都建立相同的中介語言(Intermediate Language IL)碼,以相同的 Just-in-time(JIT) 編譯器編譯。
基於以上兩點你很難說兩者的效能上有何差異
判決:平手
Using 或 Imports
C# 和 VB.NET 都提供了直接(也可以說是減少撰寫)使用 .NET Framework 架構物件的語法。例如,如果為了除錯你想要輸出一句話到 Visual Studio 視窗上,你可以利用以下的程式碼
System.Diagnostics.Debug.WriteLine("你的除錯碼")
C# 可以撰寫一模一樣的程式碼,只是加個分號。
在 C# 你可以利用 Using 命令來避免需要以全名來參照 Debug 物件,用法如下
using System.Diagnostics;
這讓你可以直接使用 Debug 物件,程式碼如下
Debug.WriteLine("除錯碼");
在 VB.NET 可以用 Imports 做到相同的事
Imports System.Diagnostics
第一眼看來這兩者是相同的,但以撰寫 Console 應用程式為例,在 C# 你要存取 Console.WriteLine 函數,需要撰寫如下
Console.WriteLine("你的輸出字串");
在這裡需要注意的是 C# 一定要定義 Console 物件的名稱。Using 語法只提供不用重複撰寫 Namespace,但與 Object 無關。在 VB.NET,你可以利用 Imports 直接提供到物件的簡寫,範例如下
Imports System.Console
所以程式碼可以更簡寫成
WriteLine("你的輸出字串")
判決:VB.NET 贏。可以直接引用的物件會帶來許多方便,尤其是在列舉一串的控制字元時。
Unmanaged Code
C# 讓你可以定義一個 unmanaged code 區塊--可以利用指標來存取 unmanaged memory。
在第一眼看來這似乎是 C# 的主要好處,但以下列理由來說,它並不見得真好
當下的 benchmarks 顯示 unmanaged code 並未比 managed code 顯著提升效能
因為 managed code 所提供的好處,強烈建議不要使用 unmanaged code(如減少 memory leak、memory 存取錯誤等等)
與一般的想法相反的是 C# 直接存取 unmanaged code 的能力並不表示你可以避免掉如 .NET interop 函數對 managed 與 unmanaged 程式碼間資料的 marshal。
VB.NET 可以完整存取 .NET interop 函數,包含呼叫任何API 函數,並使用所有標準的 marshaling 屬性從 managed memory(包括 COM 的呼叫)來 marshal 資料、物件和結構
VB.NET 可以使用 unmanaged memory,它可以獲取或釋放一個 unmanaged memory 區塊。它可以來回複製 unmanaged memory。它只是卻少內建的關鍵字,而必須要藉由 .NET interop 方法。
判決:C# 小贏
Assembly 組織
C# 讓你可以將 assembly 切成多個輸出檔案。這在你需要以多個檔案的方式來散佈應用程式時用到,如透過網路下載。VB.NET 的專案建立一個單一的輸出(DLL 或 EXE)。
因為部分散佈的方式可以同樣多個 assemblies 的方式散佈,所以很難說這是 C# 主要的好處。可能還會有人強調維護 assemblies 和可執行檔間的一對一對應是比較好維護與散佈的。
判決:C# 贏,但代價多大
(譯者註:據譯者的測試,這部分 VB.NET 也可以多個編譯過的 mod ,透過一個 manifest 以 al.exe 組成一個執行檔,似乎兩者應該是平手。但不確定是否是 Daniel Appleman 所強調的)
分別大小寫(case sensitivity)
分別大小寫也是信仰問題。C++ 的程式設計師偶爾會強調變數、方法、指令分別大小寫的重要。VB 的程式設計師則享受的不分大小寫的自由,並讓編譯器來修正他們曾經定義的變數的大小寫差異。
除了一點以外其實我們可以不討論這的問題, CLS 要求所有公共的名稱是不分大小寫的。這表示 C# 的程式設計師可以定義不同公共的成員 method1 和 Method1,從 C# 的角度來看是不同的,但對其他的 assembly 來說是相同的,這個結果會讓人混淆。所以若 C# 的程式設計師若要考慮與 CLS 相容,就必須小心不要在定義公共元素上以大小寫來區分不同。
判決:VB.NET 贏在與 CLS 相容
XML 文件
C# 讓你可以內建 XML 格式的說明文件到程式碼中,格式的範例如下
/// <summary>
/// 對於 Class1 的描述
/// </summary>
編譯器也可以對於 XML 文件做一些聰明的判斷,例如 seealso 標籤不僅僅讓編譯器建立程式碼元素交互參照,也可以確認被參照的元素是否存在,也就是說你可以有標籤如下
<seealso cref="Class2">
若在你的程式中沒有找到 Class2,編譯器會警告你。
判決:第一眼看起來 XML 文件似乎是個很好的構想。我很難判斷它是否會因此流行起來,但讓程式碼本身就具備說明能力,且讓編譯器可以不僅判讀文件的正確性,也提醒程式設計師所疏忽的公共物件與方法的文件是一個很吸引人的概念。所以我認為這是 C# 重大的贏面,並請問微軟為何 VB.NET 沒有?
語法之外的
有一些考量與語言的語法本身無關,但仍是選擇兩個語言時需要考慮的。
背景編譯與解析
C# 有一個非常聰明的分析器,幫你在編輯程式碼時標註錯誤,如漏寫分號或語法錯誤。但它畢竟不是完整的編譯器,所以無法抓到一些語意上的錯誤,如
using System.一些不存在的Namespace;
分析器在沒有編譯器的幫忙下無法方便錯誤而接受,這個錯誤要到編譯時期才會被發現。
如果你在 VB.NET 輸入相同的程式碼
Imports System.一些不存在的Namespace
VB 會立刻標出錯誤所在,並表示它找不到這個 namespace。VB 可以這麼做是因為 VB 的編譯器在你撰寫程式時已經完整地在背景執行。
問題是:收到即時錯誤有多重要?這又是一定程度的個人偏好。我相信有些程式設計師會先僅僅編寫程式,再在程式 build 時回來檢視錯誤﹔以往我個人用這種方式就已經足夠了。但以我個人的觀點來看,在開發環境提供撰寫程式時立刻錯誤檢查會大幅提升效率,我可以確定在移到下一行之前每一行程式碼都可以編譯,對我來說一開始就寫正確比事後在編譯時期發現錯誤再修改要有效率得多。
我鄭重地建議你在兩種編輯環境各花一小時來編寫程式,相信一但你熟悉了 VB.NET 的背景編譯,就會感受到沒有它的痛苦。
判決:VB.NET 大贏
從 VB6 升級
對於將 VB6 的程式碼升級到 VB.NET,我已經強調過 "移植是不聰明的",可能還不如再 .NET 建立相的程式碼,或是利用 interop system 來與已有的 COM 物件或 DLL 合作。
但仍有一些元件適合升級程式碼--尤其是希望用到 .NET free threading 特色的商業邏輯元件,或是有 memory leak 問題而希望透過 .NET 的記憶體管理獲得改善的元件。
我已經強調在大多數狀況下移植是不聰明的,若還要將 VB6 的程式碼轉成 C# 更是愚蠢至極。VB.NET 最少還提供了升級精靈來幫忙處理大部分乏味的苦工。最重要的是 VB 程式碼所使用的 Visual Basic 風格的錯誤處理與 VB.NET 和 C# 徹底不同。但與 C# 不同的是 VB.NET 仍然支援舊的錯誤處理方式,讓你在升級程式碼時可以結合新舊的錯誤處理,而不需要大費周章地重新設計錯誤處理邏輯。
不要搞錯:以 Exception 為基礎的錯誤處理是遠較 VB 舊格式的錯誤處理機制來得好。但若你需要升級舊有的程式碼,你最好還是升級錯誤處理的方式。
判決:VB.NET 大贏,但只對 VB6
聰明的格式化
C# 和 VB.NET 都提供某種程式化地自動完成語法--如自動加上結尾的大括號或是 End 區塊語法。也包含某種層度的自動縮排。
但 VB.NET 的編譯器要遠比 C# 來得聰明。我立刻發現我不再需要注意程式縮排的問題,只要讓 VB.NET 的編輯器去做就可以了,我在任何地方敲上程式碼它都可以立刻以正確的格式縮排,非常酷。
C# 在括號配對上做得不錯(所以你可以輕易分辨程式區塊),但從編輯程式的角度上來看,我仍然判定 VB.NET 贏
判決:VB.NET 徹底省掉了格式化程式的麻煩
熟悉與學習成本
熟悉語法是程式設計師最需要的,也是學新語言最貴的成本。
明顯地不管是選擇 VB.NET 或 C# 學習 .NET 都比學語法來得重要。事實上,語言是如此的相似,只要你熟悉一種語言,在幾天之內就可以熟悉另一種語言。
在短期的好處上是使用原來熟悉的語法,只要努力去了解 .NET 的架構即可
判決:VB.NET 給 Visual Basic 程式設計師,C# 給 C++ 和 Java 的程式設計師
結論
較重要的考量
下表列出明顯的差異,當你在選兩種語言時可以慎重考慮,這些比較長遠地影響開發成本
特色
贏家
背景編譯與分析
VB.NET--尤其影響撰寫程式的效率
函數回傳值
C#--自動偵測沒有回傳值的程式執行路徑
從舊有的 VB6 升級
VB.NET--要把程式碼升級到 C# 簡直就是把錢丟到水溝
XML 文件
C#--為何 VB.NET 沒有?
Event 語法
VB.NET--宣告是事件讓程式更容易瞭解並減低學習曲線
次要考量
下表列出兩個語言的次要考量,不像前述重要考量上對軟體開發生命週期長遠成本的影響。而比較偏向對先前版本的個人因素考量。
特色
贏家
Modules
VB.NET--不需要以 Class 名稱定義公共函數
Static/Shared 成員存取
C#--不會混淆 shared 和非 shared 的 class 成員
Object Syntax
VB.NET--關鍵字更符合長遠維護所需的語意易於了解
變數初始化
C#--需要在使用之前明確初始化,VB.NET 會將其初始化為 0
Shift Operators(<< 和 >>)
C#--VB.NET 沒有
VB 關鍵字
VB.NET--減少 VB6 程式設計師的學習曲線。對於 C++ 的程式設計不重要。
熟悉程度
VB.NET 對 VB,C# 對 C++ 和 Java
Switch/Select Case
VB.NET--讓 case 的元素可以常數和變數組合
Unmanaged Code
C#--VB.NET 要透過 .NET interop 的各種方法存取 unmanaged memory
Assembly Organization
C#--VB.NET 將每個 Assembly 建成單一的 exe 或 dll
程式碼結構化(編輯的結構化)
VB.NET--自動格式化,不會有任何縮排的錯誤
選擇性參數
VB.NET--C# 可以 overloads 做到相同的事情
考量是否與 CLS 相容
下表列出是否你需要考慮與 CLS 相容的各點
特色
贏家(如果你考慮與 CLS 相容)
贏家(如果你不考慮與 CLS 相容)
Unsigned 變數
VB.NET -- 減少使用上發生錯誤
C#--VB.NET 沒有
運算子 Overloading
VB.NET -- 減少使用上發生錯誤
C#--VB.NET 沒有
Custom Conversions
VB.NET -- 減少使用上發生錯誤
C#--VB.NET 沒有
區分大小寫
VB.NET -- 減少轉換上發生錯誤
完全個人喜好