自1991 年Visual Basic 語言誕生之日起,它就一直是產生應用程式的高效率工具。將近20 年後,它繼續提供與Microsoft .NET Framework 的輕鬆對接,使開發人員能夠編寫可跨越桌面、電話、瀏覽器甚至雲端的應用程式。
Microsoft 將在本月發布Visual Studio 2010,其中包含Visual Basic 版本10(有時稱為VB 2010 或VB10)。此版本是迄今為止最強大的版本,包含許多省時省力的功能,可以幫助開發人員透過更少的程式碼行完成更多的操作。在這裡,將會為您提供所有必要的內容,讓您充分了解並利用Visual Studio 2010 中的Visual Basic。
共同演變
在過去,Visual Basic 和C# 是由獨立團隊分別開發的,這通常會導致一些功能先出現在一種語言中,然後又出現在另一種語言中。例如,C# 有Visual Basic 中所沒有的自動實作屬性和集合初始值設定項,而Visual Basic 則有C# 中所沒有的晚期綁定和可選參數等功能。但每當一種語言具有新功能時,許多客戶都會要求將該功能也新增到另一種語言中。
為了解決這個需求,Microsoft 合併了Visual Basic 和C# 團隊,實行共同演進的策略。目的是為推動這些語言共同發展。當一種語言中引入重大功能時,它也會出現在另一種語言中。這並不是說每種功能都會出現在兩種語言中,並以完全相同的方式運作;實際上,每種語言都有自己的歷史、靈魂和感覺– 保留這些特性非常重要。
在.NET Framework 4 中,Visual Basic 和C# 朝著這個目標邁進了一大步,分別吸收了對方既有的許多功能。然而,共同演化不僅影響到先前的功能;它同樣是這些語言未來的發展策略。本著這種精神,.NET Framework 4 在兩種語言中同時引入了強大的新功能,例如動態語言運行時、嵌入式互操作類型和泛型方差,從而使Visual Basic 和C# 開發人員能夠充分利用.NET Framework。
Visual Basic 2010 新增功能
Visual Basic 2010 中的新功能旨在協助您透過更少的程式碼行實現更多操作。我們Visual Basic 設計團隊仔細研究了開發人員通常必須編寫大量繁瑣樣板程式碼的地方,並找到相應解決方案,讓編譯器取代執行此類工作。當然,這是從整體來看,現在就讓我們深入了解各項功能。
隱式行繼續符
Visual Basic 是一種以行為導向的語言,它使用類似於英文的清晰語法來增強可讀性。但這通常會導致程式碼遇到每行80 個字元的限制,從而迫使開發人員要進行大量滾動。您可以使用下劃線字元來告知編譯器應將下一行作為目前行繼續處理(也就是說,將多個實體行視為單一邏輯行)。但不得不重複地鍵入下劃線字元一直很令人煩惱,而事實上多年來排在首位的功能請求就是讓編譯器解決這個問題。
而在Visual Basic 2010 中,編譯器能夠解決這個問題。編譯器現在知道哪些標記(例如逗號、圓括號和運算符)往往出現在行繼續符前面,並且它會插入字符,因此開發人員不再需要插入字符。例如,用逗號作為Visual Basic 語句的結尾肯定不合邏輯;編譯器知道這一點,因此,當編譯器看到諸如{comma, enter} 這樣的標記流時,它會推斷出存在行繼續符,如圖1 中的範例所示。
圖1 推斷出行繼續符
<Extension()>
Function FilterByCountry(
ByVal customers As IEnumerable(Of Customer),
ByVal country As String) As IEnumerable(Of Customer)
Dim query =
From c In customers
Where c.Country = country
Select <Customer>
<%=
c.Name &
, &
c.Country
%>
</Customer>
Return query
End Function
在Visual Basic 2008 中,圖1 中的程式碼將需要9 個底線字元。然而,在以下每種情況下,編譯器會推斷下劃線字元在何時是必要的,並允許將其忽略:
在<Extension()> 屬性之後
在方法宣告中的((左圓括號)之後
在第一個參數的,(逗號)之後
在方法宣告中的)(右圓括號)之前
在=(等號)之後
在<%=(嵌入式表達式的開始標記)之後
在XML 文字的每個&(與號)之後
在%>(嵌入式表達式的結束標記)之前
這個新的編譯器功能對於方法簽章特別有用,它對於所示範例中超過80 個字元的情況也將正常運作(如果每一部分都位於同一行上)。在圖2 中,您將看到行繼續符為隱式的標記和位置的所有組合。
圖2 行繼續符為隱式的情況
標記 | 之前 | 之後 |
,(逗號)、.(句點)、>(屬性)、( {(左括號)、<%=(內嵌表達式開始標記(XML 文字)) | X | |
)、}、](右括號)、%>(嵌入式表達式結束標記) | X | |
所有LINQ 關鍵字: Aggregate、 Distinct、From、Group By、Group Join、Join、Let、Order By、Select、Skip、Skip While、Take、Take While、Where、In、Into、On、Ascending、Descending | X | X |
運算符: +、 -、*、/、/、^、>>、<<、Mod、&、+=、-=、*=、/=、/=、^=、>>=、<& lt;=、 &=、<、<=、>、>=、<>、Is、IsNot、Like、And、Or、Xor、 AndAlso、OrElse | X | |
With(在物件初始值設定項中) | X |
如您所見,有60 多個該語言不需要下劃線字元的地方。 (事實上,本文中的任何一個程式碼範例都不需要行繼續符。)當然,您仍然可以使用下劃線字符,因此Visual Basic 先前版本中的程式碼將仍然按預期方式編譯。
語句Lambda
術語lambda 乍聽起來可能很嚇人,但lambda 只是在另一個函數內定義的函數。 Visual Basic 2008 引入了帶有Function 關鍵字的lambda 表達式:
Dim customers As Customer() = ...
Array.FindAll(customers, Function(c) c.Country = Canada)
Lambda 表達式可讓您在本機上以細緻緊湊的方式表達邏輯,而不必跨多個方法拆分邏輯。例如,以下是Visual Basic 2005(不支援lambda 表達式)中先前的程式碼的表示形式:
Dim query = Array.FindAll(customers, AddressOf Filter)
…
Function Filter(ByVal c As customer) As Boolean
Return c.Country = Canada
End Function
不幸的是,Visual Basic 2008 的lambda 表達式要求表達式傳回值,因此以下程式碼:
Array.ForEach(customers, Function(c) Console.WriteLine(c.Country))
將會導致以下情況:
'Compile error: Expression does not produce a value.
Console.WriteLine 是一個Sub 過程(C# 中為void),因此它不會傳回值,而這就是編譯器產生錯誤的原因所在。為了處理此情況,Visual Basic 2010 引入了對語句lambda 的支持,後者是包含一個或多個語句的lambda:
Array.ForEach(customers, Sub(c) Console.WriteLine(c.Country))
由於Console.WriteLine 不傳回值,因此我們可以只建立Sub lambda,而不是Function lambda。以下是使用多個語句的另一個範例:
Array.ForEach(customers, Sub(c)
Console.WriteLine(Country Name:)
Console.WriteLine(c.Country)
End Sub)
當此程式碼運行時,它將為每個客戶列印兩行。另外請注意,如果在編碼時懸停在c 上,您將看到編譯器會將類型推斷為Customer(鍵入c As Customer 來明確聲明類型也是合法的)。動態編寫事件處理程序是語句lambda 的另一個絕佳用途:
AddHandler b.Click, Sub(sender As Object, e As EventArgs)
MsgBox(Button Clicked)
'insert more complex logic here
End Sub
並且,事實上,您可以將語句lambda 與Visual Basic 2008 中引入的一項功能(鬆散委託)結合使用。 (可以使用委託– 類型安全的函數指標– 一次執行多個函數。)這種組合將產生更為簡單的簽章:
AddHandler b.Click, Sub()
MsgBox(Button Clicked)
'insert more complex logic here
End Sub
委託鬆散使您可以完全忽略事件處理程序中的參數– 這是一個很好的優點,只要它們根本未使用過,因此它們只會在視覺上帶來幹擾。
除了目前為止我們已看到的單行Sub lambda 和多行Sub lambda 外,Visual Basic 2010 還支援多行Function lambda:
Dim query = customers.Where(Function(c)
'Return only customers that have not been saved
'insert more complex logic here
Return c.ID = -1
End Function)
語句lambda 的另一個引人關注的面向是它們與Visual Basic 2008 所引入的匿名委託的相交方式。人們經常將這些委託與C# 的匿名方法混淆,儘管嚴ge來說它們並不相同。當Visual Basic 編譯器基於lambda 的方法簽章推斷委託類型時,將會發生匿名委託:
Dim method = Function(product As String)
If product = Paper Then
Return 4.5 'units in stock
Else
Return 10 '10 of everything else
End If
End Function
MsgBox(method(Paper))
如果運行此程式碼,您將看到訊息框中顯示值4.5。此外,如果懸停在method 上,您將看到文字Dim method As <Function(String) As Double>。由於我們未提供實際委託類型,因此編譯器將自動產生一個委託類型,如下所示:
Delegate Function $compilerGeneratedName$(product As String) As Double
這稱為匿名委託,因為它只會出現在編譯器產生的程式碼中,而不會出現在編寫的程式碼中。請注意,當事實上沒有提供As 子句來指定lambda 的回傳類型時,編譯器會傳回類型推斷為Double。編譯器會檢視lambda 內的所有回傳語句,並將決定類型Double (4.5) 和Integer (10):
'Notice the As Single
Dim method = Function(product As String) As Single
If product = Paper Then
Return 4.5 'units in stock
Else
Return 10 '10 of everything else
End If
End Function
然後,它將運行其基準類型演算法,並確定它能夠安全地將10 轉換為Double,但無法安全地將4.5 轉換為Integer;因此Double 是更好的選擇。
您也可以明確控制返回類型,在這種情況下,編譯器將不會嘗試推斷類型。非常常見的做法是將lambda 賦予具有明確委託類型的變量,而不是依賴編譯器來推斷委託類型:
Dim method As Func(Of String, Single) =
Function(product)
If product = Paper Then
Return 4.5 'units in stock
Else
Return 10 '10 of everything else
End If
End Function
由於提供了明確目標類型,因此無需聲明As String 或As Single;編譯器可基於語句左邊的委託類型來推斷其存在。因此,如果您懸停在product 上,將會發現推斷出的類型為String。不再必須指定As Single,因為委託類型已提供該資訊。在前面的範例中,Func 委託(.NET Framework 包含該委託)的簽名如下所示:
Delegate Function Func(Of T, R)(ByVal param As T) As R
但有一個很小的例外之處,稍後我們將在泛型方差一節中看到。
自動實現的屬性
在Visual Basic 中,屬性是用於向外部公開物件狀態的類別成員。典型的屬性聲明與如下聲明類似:
Private _Country As String
Property Country As String
Get
Return _Country
End Get
Set(ByVal value As String)
_Country = value
End Set
End Property
一個其實非常簡單的概念就有10 行程式碼。由於典型的物件通常有數十個屬性,因此您最終會在類別定義中包含大量樣板程式碼。為了簡化此類任務,Visual Basic 2010 引入了自動實現的屬性,利用該屬性,您只需使用一行程式碼即可定義簡單的屬性:
Property Country As String
在這種情況下,編譯器將繼續運作並自動產生Getter、Setter 和支援欄位。支援欄位的名稱是始終為前面帶有底線字元的屬性的名稱:此範例中為_Country。這種命名約定在將自動實現的屬性變更為常規屬性的情況下確保了二進位序列化相容性。只要支援欄位的名稱相同,二進位序列化就將繼續工作。
您可使用自動實作的屬性執行的其中一項出色的功能是:指定在建構函式執行時設定屬性預設值的初始值設定項。舉例來說,一個帶有實體類別的常見方案將主鍵設為類似-1 的值,以指示其處於未儲存的狀態。程式碼將如下所示:
Property ID As Integer = -1
當建構函式運行時,支援欄位(_ID) 將自動設定為值-1。初始值設定項語法也適用於參考類型:
Property OrderList As List(Of Order) = New List(Of Order)
由於無需輸入兩個類型的名稱,因此上一行程式碼可能不會具有非常明顯的Visual Basic 特徵。好消息是,常規變數聲明中有一個與Visual Basic 所允許語法一致的更短的語法:
Property OrderList As New List(Of Order)
您甚至能夠將此語法與物件初始值設定項結合使用,以允許設定其他屬性:
Property OrderList As New List(Of Order) With {.Capacity = 100}
很顯然,對於更複雜的屬性,擴展的語法仍然是必要的。您仍可以鍵入Property{Tab} 來啟動舊屬性片段。或者,在鍵入屬性的第一行後,您可以只輸入Get{Enter},IDE 將產生舊樣式的屬性:
Property Name As String
Get
End Get
Set(ByVal value As String)
End Set
End Property
人們通常會發現:新的屬性語法與公共欄位的語法幾乎相同,那麼為什麼不改為使用公共欄位?有幾個原因:
大多數.NET 資料綁定基礎結構都依據屬性(而不是欄位)工作。
介面無法強制要求存在欄位;但可以強制要求存在屬性。
屬性為更改業務規則提供了更長期的靈活性。例如,假定某人引入了電話號碼必須為10 位數的規則。如果指派給公共字段,將無法執行此驗證。對於諸如二進位序列化和反射等方案而言,將公共欄位變更為屬性是一項重大變更。
集合初始值設定項
一種常見.NET 做法是實例化集合,然後透過為每個元素呼叫一次Add 方法來填入該集合:
Dim digits As New List(Of Integer)
digits.Add(0)
digits.Add(1)
digits.Add(2)
digits.Add(3)
digits.Add(4)
digits.Add(5)
digits.Add(6)
digits.Add(7)
digits.Add(8)
digits.Add(9)
但對於從根本上來說非常簡單的概念來說,將會產生大量語法開銷。 Visual Basic 2010 引入了集合初始值設定項,讓您更容易實例化集合。對於此程式碼:
Dim digits = New List(Of Integer) From {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
編譯器將自動產生對Add 方法的所有呼叫。您也可以使用Visual Basic 的As New 語法的功能:
Dim digits As New List(Of Integer) From {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
請注意,在Visual Basic Team 上,我們一直建議使用第二種語法(As New),而不是前者,因為它使程式碼更能適應Option Infer 設定的變更。
您可以依據滿足以下要求的任何類型使用集合初始值設定項目:
您可以使用For Each 語句循環存取該類型– 也就是說,該類型實作IEnumerable。 (有關集合類型更精確/詳細的定義,請參閱msdn.microsoft.com/library/aa711986(VS.71).aspx 上Visual Basic 語言規範的第10.9.3 節)。
此類型具有可存取的(但不一定是公共)無參數建構函數。
該類型具有可存取的(但不一定是公共)實例或名為Add 的擴充方法。
這意味著,您也可以將集合初始值設定項目用於更複雜的類型,例如字典:
Dim lookupTable As New Dictionary(Of Integer, String) From
{{1, One},
{2, Two},
{3, Three},
{4, Four}}
(請注意,即使此語句跨了五行,也沒有下劃線字元。)在這種情況下,編譯器將產生與初始化字典的舊方法等效的程式碼:
Dim lookupTable As New Dictionary(Of Integer, String)
lookupTable.Add(1, One)
lookupTable.Add(2, Two)
lookupTable.Add(3, Three)
lookupTable.Add(4, Four)
編譯器在呼叫具有兩個參數(而不是一個參數)的Add 方法。它之所以知道這樣做,原因是傳入集合初始值設定項的值位於嵌套的大括號中,如下所示:{{1, One}, {2, Two}, …}。對於每一組巢狀的大括號,編譯器會嘗試將這些參數傳遞到相容的Add 方法。
也可以透過使用擴充方法來提供您自己的自訂Add 實作:
<Extension()>
Sub Add(ByVal source As IList(Of Customer),
ByVal id As Integer,
ByVal name As String,
ByVal city As String)
source.Add(New Customer With
{
.ID = id,
.Name = name,
.City = city
})
End Sub
(看看所有這些缺少的下劃線字元!)此方法擴展任何實作IList(Of Customer) 的類型,然後允許您使用新的集合初始值設定項語法,如下所示:
Dim list = New List(Of Customer) From
{
{1, Jon, Redmond},
{2, Bob, Seattle},
{3, Sally, Toronto}
}
(向清單中新增三個客戶)。您也可以將集合初始值設定項目與自動實作的屬性結合使用:
Property States As New List(Of String) From {AL, AK, AR, AZ, ...}
數組文字
除了更強大的集合類型處理方式外,Visual Basic 2010 還提供了一些用於處理陣列的強大增強功能。假設有以下程式碼(在較舊版本中可正常運作):
Dim numbers As Integer() = New Integer() {1, 2, 3, 4, 5}
透過查看該數組中的元素,很明顯每個元素都是整數,因此,必須實際上在此行中列印輸出兩次Integer 的操作不會真正添加任何值。陣列文字允許將某個陣列的所有元素放在大括號內,然後讓編譯器自動推斷類型,從而建立該陣列:
Dim numbers = {1, 2, 3, 4, 5}
numbers 的類型不是Object,而是Integer()(只要啟用了Option Infer),原因是數組文字現在可代表本身,並且有自己的類型。假設有一個更複雜的例子:
Dim numbers = {1, 2, 3, 4, 5.555}
在這種情況下,numbers 的類型將推論為Double()。編譯器透過檢查數組中的每個元素併計算基準類型(所使用的演算法與前面討論的用於推斷語句lambda 的返回類型的演算法相同),從而確定類型。如果沒有基準類型將會發生什麼情況?例如,以下程式碼中所示:
Dim numbers = {1, 2, 3, 4, 5}
在這種情況下,將Integer 轉換為String 將會縮小轉換範圍(也就是說,在執行時可能會出現資料遺失的情況),同樣,將String 轉換為Integer 也會縮小轉換範圍。可選擇的唯一安全的類型為Object()(如果啟用了Option Strict,編譯器將產生錯誤)。
可以嵌套數組文字以形成多維數組或交錯數組:
'2-dimensional array
Dim matrix = {{1, 0}, {0, 1}}
'jagged array - the parentheses force evaluation of the inner array first
Dim jagged = { ({1, 0}), ({0, 1}) }
動態語言執行時期
儘管Visual Basic 從技術上而言實質上是靜態語言,但它一直有非常強大的動態功能,例如晚期綁定。 Visual Studio 2010 附帶了一個名為動態語言執行時期(DLR) 的新平台,利用該平台可更為輕鬆地產生動態語言– 並在這些語言之間通訊。 Visual Basic 2010 已更新為在其晚期綁定程式中完全支援DLR,使開發人員能夠使用採用其他語言(例如IronPython/IronRuby)開發的程式庫和框架。
此功能的一項突出優點是,從語法上而言沒有任何內容發生變更(事實上,在編譯器中沒有修改任何一行程式碼來支援此功能)。開發人員仍然能夠像在Visual Basic 先前的版本中一樣進行晚期綁定的操作。改變的是Visual Basic 運行庫(Microsoft.VisualBasic.dll) 中的程式碼,現在可識別DLR 提供的IDynamicMetaObjectProvider 介面。如果某個物件實現此接口,則Visual Basic 運行庫將建構DLR CallSite,並允許該物件及提供該物件的語言將它們自己的語義注入操作。
例如,Python 標準函式庫包含一個名為random.py 的文件,其中有一個名為shuffle 的方法,可用於隨機重新排列數組中的元素。呼叫該方法很簡單:
Dim python As ScriptRuntime = Python.CreateRuntime()
Dim random As Object = python.UseFile(random.py)
Dim items = {1, 2, 3, 4, 5, 6, 7}
random.shuffle(items)
在執行時,Visual Basic 會看到物件實作IDynamicMetaObjectProvider,並因此將控制權交給DLR,後者隨後將與Python 通信,並執行該方法(將Visual Basic 中定義的陣列作為參數傳遞給該方法)。
這是呼叫啟用了DLR 的API 的一個範例,但開發人員也可以建立他們自己的使用此功能的API。關鍵是實作IDynamicMetaObjectProvider 接口,在這種情況下,Visual Basic 和C# 編譯器將可識別具有特殊動態語義的物件。請不要手動實作該接口,更簡單的方法是:從System.Dynamic.DynamicObject 類別(該類別已實作此介面)繼承並僅重寫少數幾個方法。圖3 顯示了建立自訂動態物件(一種似乎可即時建立屬性的屬性套件)並使用正常Visual Basic 晚期綁定來呼叫該物件的完整範例。 (有關使用DynamicObject 的詳細信息,請閱讀Doug Rothaus 撰寫的非常不錯的文章,網址為blogs.msdn.com/vbteam/archive/2010/01/20/fun-with-dynamic-objects-doug-rothaus.aspx 。
圖3 建立自訂動態物件並使用Visual Basic 晚期綁定呼叫該對象
Imports System.Dynamic
Module Module1
Sub Main()
Dim p As Object = New PropertyBag
p.One = 1
p.Two = 2
p.Three = 3
Console.WriteLine(p.One)
Console.WriteLine(p.Two)
Console.WriteLine(p.Three)
End Sub
Class PropertyBag : Inherits DynamicObject
Private values As New Dictionary(Of String, Integer)
Public Overrides Function TrySetMember(
ByVal binder As SetMemberBinder,
ByVal value As Object) As Boolean
values(binder.Name) = value
Return True
End Function
Public Overrides Function TryGetMember(
ByVal binder As GetMemberBinder,
ByRef result As Object) As Boolean
Return values.TryGetValue(binder.Name, result)
End Function
End Class
End Module
泛型變異數
這是一項乍聽起來的確可能很複雜的功能(帶有像協方差和逆變這樣的術語),但實際上它很簡單。如果您有類型為IEnumerable(Of Apple) 的對象,並且希望將其指派給IEnumerable(Of Fruit),這應該是合法的,因為每個Apple 都是Fruit(由繼承關係強制要求)。遺憾的是,在Visual Basic 2010 之前,編譯器中不支援泛型方差,即使公共語言運行時(CLR) 中實際上支援泛型方差也是如此。
讓我們看一下圖4 中的範例。在Visual Basic 2008 中,圖4 中的程式碼將在Dim enabledOnly 行上產生編譯錯誤(或者,如果停用了Option Strict,則產生執行時期異常)。解決方法是呼叫.Cast 擴充方法,如下所示:
'Old way, the call to Cast(Of Control) is no longer necessary in VB 2010
Dim enabledOnly = FilterEnabledOnly(buttons.Cast(Of Control))
這一點不再必要,因為在Visual Basic 2010 中,已透過使用Out 修飾符將IEnumerable 介面標記為協變:
Interface IEnumerable(Of Out T)
…
End Interface
圖4 泛型變異數範例
Option Strict On
Public Class Form1
Sub Form1_Load() Handles MyBase.Load
Dim buttons As New List(Of Button) From
{
New Button With
{
.Name = btnOk,
.Enabled = True
},
New Button With
{
.Name = btnCancel,
.Enabled = False
}
}
Dim enabledOnly = FilterEnabledOnly(buttons)
End Sub
Function FilterEnabledOnly(
ByVal controls As IEnumerable(Of Control)
) As IEnumerable(Of Control)
Return From c In controls
Where c.Enabled = True
End Function
End Class
這意味著泛型參數T 現在為變數(也就是說,它適用於繼承關係),並且編譯器將確保僅在類型來自於介面的位置使用該參數。泛型參數也可以是逆變量,這意味著它們僅在輸入位置使用。類型可實際上具有這兩者。例如,前面討論的Func 委託既具有逆變參數(傳入的內容),也具有協變參數(用於返回類型):
Delegate Function Func(Of In T, Out R)(ByVal param As T) As R
可以在自訂介面和委託上使用In 和Out 修飾符。 .NET Framework 4 中的許多常用介面和委託已標記為變數;常見範例包括所有Action/Func 委託、IEnumerable(Of T)、IComparer(Of T) 和IQueryable(Of T) 等。
泛型變異數的突出優點是:它是一項您完全無需擔心的功能– 如果它在執行工作,您將絕對不會注意到它。曾經會導致編譯器錯誤或要求呼叫.Cast(Of T) 的情況在Visual Basic 2010 中運作正常。
改進的可選參數
可選參數提供了一種有用的高效功能,它使開發人員能夠建立更靈活的方法,並避免使用許多方法重載使類別混亂不堪。在過去有一點限制,即可選參數不能為null(或甚至不能為任何非內部結構類型)。 Visual Basic 2010 現在可讓您定義任意值類型的選用參數:
Sub DisplayOrder(ByVal customer As Customer,
ByVal orderID As Integer,
Optional ByVal units As Integer? = 0,
Optional ByVal backgroundColor As Color = Nothing)
End Sub
在此範例中,units 的類型為Nullable(Of Integer),backgroundColor 為非內容結構類型,但仍將它們用作可選參數。 Visual Basic 2010 也為泛型可選參數提供了更好的支援。
嵌入式互通類型
對於執行COM 互通的應用程序,一個常見弱點是必須使用主互通程序集(PIA)。 PIA 是一種.NET 組件,它可作為COM 元件上的執行時間可呼叫包裝(RCW),並具有用來識別它的唯一GUID 。 .NET 程式集與PIA 通信,後者隨後執行任何必要的封送以在COM 和.NET 之間移動資料。
遺憾的是,PIA 可能會使部署變得很複雜,因為它們是需要部署到最終用戶電腦的附加DLL。它們也可能會導致版本控制問題– 例如,如果您希望應用程式能夠同時依據Excel 2003 和Excel 2007 工作,則將需要隨應用程式同時部署兩個PIA。
嵌入式互通類型功能直接嵌入應用程序,但只會嵌入絕對必要的PIA 中的類型和成員,因此無需將PIA 部署到最終用戶的電腦。
若要為現有物件啟用此功能(對於新引用,預設情況已啟用此功能),請在解決方案資源管理器中選擇引用,並在屬性視窗中變更Embed Interop Types選項(請參閱圖5)。或者,如果使用ming令行編譯器進行編譯,請使用/l(或/link)開關,而不是/r 和/reference。
圖5 在解決方案資源管理器中啟用嵌入式互通類型
啟用此功能之後,應用程式將不再依賴PIA。事實上,如果在Reflector 或ildasm 中開啟程式集,您將注意到實際上根本沒有對PIA 的任何參考。
多重目標
Visual Basic 2010 中所有功能最突出的特點是:您甚至可以在目標為.NET Framework 2.0 至.NET Framework 3.5 的專案中使用這些功能。這意味著,隱式行繼續符、陣列文字、集合初始值設定項、語句lambda、自動實現的屬性等功能將全部都可在現有項目中使用,而不必將目標重定為.NET Framework 4 。
例外情況是嵌入式互通類型,它依賴於只有.NET Framework 4 中才有的類型;因此,如果將目標定為.NET Framework 版本2.0 至3.5,則無法使用該功能。此外,只會採用.NET Framework 4 中的方式對標記為變數的型別進行標記,因此,在前面的範例中,如果將目標定為版本2.0 至3.5,則仍必須呼叫.Cast(Of T)。不過,如果將目標定為這些早期版本,您可以建立自己的變數類型(使用In/Out 修飾符)。
若要變更應用程式的目前目標框架,請雙擊我的項目,按一下編譯選項卡,按一下進階編譯選項,然後從底部的組合方塊中進行選擇。
從ming令行中進行編譯時,實際上沒有ming令行開關可啟用此功能。實際上,編譯器將查看哪個組件提供了System.Object 的定義(通常為mscorlib)以及組件的目標定為哪個框架,然後在輸出程式集中標記該值。 (編譯器在產生Silverlight 程式集時也使用這個相同的機制。)在使用IDE 時,所有這些都是以透明方式進行的,因此通常您無需擔心任何事情。
歡迎試用
如您所見,Visual Basic 2010 具有許多強大功能,這些功能可讓您提高工作效率,同時減少編寫的程式碼行數,而將更多工作交給編譯器來做。在本文中,我只探討了語言功能,但Visual Basic 2010 IDE 還有無數的優異增強功能。以下列出部分增強功能:
導航到
突出顯示引用
從使用中生成
更好的IntelliSense(子字串匹配、駝峰式大小寫查找、建議模式– 對於首先測試開發風ge非常有用)
多監視器支援
縮放
Visual Basic 團隊渴望聽到您對我們改善Visual Basic 的工作方面的回饋,因此請在Microsoft Connect 上將您的意見和問題發送給我們。若要了解有關語言和IDE 功能的詳細信息,請查看msdn.com/vbasic 上的內容,其中包括文章、範例和操作方法影片。當然,最佳學習方式是深入研究和使用產品,因此是安裝和試用產品的時候了。