Visual Basic 14: 14 個重大的改進

    Visual Basic 14 是最新版本的 Visual Basic, 隨著 Visual Studio 2015 發佈。這邊從不同的面向挑出了 14 個重要的改進來做個介紹。

更好的編程體驗 

1. 重構

    過去我們必需使用第三方的套件產品以獲取足夠的重構功能,像是 Extract method,Inline variable。在 Visual Studio 2015 這部份已經內建,不再需要安裝第三方套件的輔助。使用上只要點選 identifier,或是將子運算式選取起來,按下 Ctrl + . 或是按下滑鼠右鍵後選取 Quick Actions。light bulb 的選單會有相關的動作,可參閱圖一。

圖 1 Visual Basic 14 內建重構功能

注意到這邊,重構是 context-aware 的。舉個例子來說,如果你將 “Dim circleArea = Math.PI * radius * radius” 右邊的運算式擷取到方法中, Visual Basic 會建議使用 “GetCircleArea” 當作方法的名稱. 且會切到 inline-rename 模式,如果再進一步將方法名稱改成已經在使用的名稱,它會偵測到命名衝突並提出警告。 

2. Analyzers  

    Analyzers 可以把 light bulbs、code actions 和錯誤的建議交給你制定。 你可以用它們來執行整個團隊的程式碼規範. 如果要除錯問題,也可以加裝 analyzer 找出方案中有哪些常見的程式碼缺陷。 許多我們使用的函式庫因為內建有自己的 analyzers 所以變成程式碼感知. 舉個例子來說, 假設你沒用過 Microsoft Azure Storage 函式庫或是沒有看過最佳實踐的文章。因為該函式庫現在有放入 analyzer 去偵測 API 使用上常犯的錯誤,所以你可以立即的確定你是否有正確的使用。就像是有個專業的程式碼審查人員在幫你審查程式碼一樣。 

你可以透過方案總管上的 References | Analyzers 節點將 analyzers 加入到你的專案, (或是透過 NuGet)。一旦將他加到專案中,即會在輸入時即時運行分析並給予建議。 當使用 Visual Studio 、命令列、甚至是在建置伺服器上建置專案時也都會運行分析. Analyzers 可給予我們機會去觸碰到編譯器的內部, 查看專案程式碼的語法樹以及其類型與成員。 開發人員會發現他們可以很容易的將專業領域知識編寫成 Analyzers,這都要歸功於這些語法樹以及其類型與成員。我最愛的其中一個程式分析器,是幫我分析並警告是否誤用了 Async Sub Method 而沒有用 Async Function 。 不是很多人注意到這個非同步程式撰寫重點,但這個有點極端,然而這錯誤會導致難以偵錯的同步運行的bug,因此,如果能再編譯時期就發現這樣的問題,對整個團隊是很好的。若想撰寫自己的 Analyzers ,可以參閱 roslyn.codeplex.com。 

3. 不需將游標移開以更新錯誤警示 

    VB 的使用者, 你可能在輸入程式碼, 然後快速的將游標移至下方後再往上移回,看看是否會浮現任何的錯誤警示. 或者是你正在進行錯誤的修正, 但必須要快速的將游標移至下方後再往上移回,錯誤警示才會消失。現在你不需要再這樣做了。錯誤警示會自動顯示或浮現。 

4. XML 註解的參考 

你熱衷於 XML 註解?這邊有個小小的例子:

 ''' <summary>
''' Similar to <see cref="List(Of Integer).Count"/>
''' </summary>
''' <param name="e">Thing to count</param>
''' <remarks></remarks>
Sub Count(e As IEnumerable)
End Sub

在先前的 VB 版本,當你在註解上輸入 cref 與 param-name,會有 completion-list 輔助。編譯器會做最小幅度的驗證,檢查輸入的名稱是否存在,但名稱會用灰色,不易發現、查詢、或重構。 在 Visual Basic 14,cref 與 param-name 參數會被正確的著色。你可以將滑鼠移至上面去查看相關的提示。當你重新命名,Visual Basic 會將所有參照到的地方都一併更名,包含 cref 與 param-name。你可以在上面按下滑鼠右建,選取移至定義,或是找尋所有參照。如果你想要參照的方法有很多多載,你現在也可以指定參照某一多載版本。這些改變會讓我們在註解上做些參照時更為便利。 

專案系統的基本功能

5. 方案總管的參考節點

圖二顯示 Visual Basic 14 專案在方案總管中會怎樣呈現。

圖 2 參考節點現在會在方案總管中顯現

以往參考節點通常是隱藏的,需要按下顯示所有檔案按鈕才能看到,但這也表示會連帶顯示很多部相關的檔案。

這樣的行為在 10 年前可能是對的,像是當你使用 Windows Forms 專案,它會幫你加入正確的參考。但是以現代化的開發方式來說,參考節點會很常被使用到—特別是在管理 NuGet 的參考。能直接在方案總管看到,這是很小的修改但會讓開發上更為便利。

6. Shared Projects

    假設你想要在多個專案共用程式. 這是在普遍也不過的情境了, 舉個例子來說,假設你要同時維護 WPF 程式與 Windows Phone 的 app. 目標是將程式碼重用性最大化, 像是發生問題時我們只要修復一個地方就好.

在過去, 你可以選擇兩種不同的方式去做: 像是使用檔案連結的方式去分享相同的程式碼。或是調整程式架構將共用的程式放入 Portable Class Library,讓不同的專案共享相同的組件。現在 Visual Basic 14 提供第三種方式: Shared Projects.

為什麼你應該使用 Shared Projects? 程式碼共用是很大的挑戰,沒有一個所有情境都適用的解決方案。 Portable Class Libraries 是一很好且乾淨的解決方案, 但它強迫你從程式架構面下去改善,共用的程式無法叫用到 WPF 或是 Phone 專案; 只能叫用 WPF 與 Phone 系統都可以使用的 API。 Shared Projects 相較起來容易使用的多,因為不需要對程式的架構進行調整。

要建立 Shared Project,我們可以在方案上按下滑鼠右鍵,選取 Add | New Project | VB | Shared Project。接著在每個專案的參考節點上按下滑鼠右鍵,選取 Add | Shared Projects。Shared Project 內可放置程式碼、XAML 檔、圖檔、以及其它每個專案都要參考到的東西。

透過 My Project | Compile | Advanced Compile Options | Custom Constants 我們可為每個專案設定自訂的常數,像是 WPF 與 PHONE。在共用的程式中就可以像下面這樣針對不同的專案做出不同的處理:

 #If WPF Then
  ' nothing needed
#ElseIf PHONE Then
  ShowBatteryStatus()
#End If

7. 加速 50% 編譯時間

    Visual Basic 的編譯器過去是用 C++ 撰寫的。到了 Visual Basic 14, 開發團隊將它全部用 VB 重寫,讓編譯器變得非常的快速!這邊有兩組對照:

大型方案建置 (130 萬行程式碼) 時間從 68 秒降到 41 秒。

一個 Windows 市集的應用程式載入時間從 6.7 秒降到 4.6 秒。

這改進了非常多的時間. 這是很重要的,有助於維持開發時的思緒,不會在完成程式後按下 F5 編譯就被長時間的編譯給打斷。

 50% 的效能增進可能會令人很驚訝,因為以語言的層面來說, C++ 應該比 VB 來的要快的多。事實上,效能上的增進主要是來自演算法、資料結構、與並行這幾個面向的改進。像是重新思考資料結構; 更清晰的演算法; 使用 async 與 threadpool; 使用 Visual Studio 分析工具去找出 CPU 與記憶體的瓶頸; 使用 analyzers 去找出不必要的 .NET 效能陷阱像是 boxing。 

8. 在監看視窗使用 Lambdas 與 LINQ 陳述式

    LINQ 與 lambdas 是做匯總資料不錯的方法。一個最常需要使用的地方就是在用監看視窗或即時運算視窗除錯的時候。在過去,我們無法在這兩個除錯視窗上面使用 LINQ 或是 Lambda 運算式,一嘗試使用就會出現下列錯誤訊息:

Evaluation of lambda expressions is not valid in the debugger. 

現在,在新版的程式這已開始支援(參閱圖三)!舉個例子來說,如果程式中有個集合叫 customers,在除錯時我們可以在監看視窗中像下面這樣撰寫以快速的讀取這個集合內的資料: 

From c In customers Where c.OrderStatus = "Unfulfilled" Select c.LastName 

圖 3 在監看視窗中使用 Lambdas 與 LINQ 運算式

你知道你可以在不啟動程式的狀態下使用即時運算視窗嗎?舉個例子來說,假設剛寫了個 GetName 的方法,可以在即時運算視窗中輸入 "? GetName()",即會立即運行。 Visual Studio 2015 的 Edit and Continue 功能對於非同步與迭代方法也有更好的支援,允許你加新的 LINQ 與 Lambda 語法到現有的方法中。雖然這功能在 Visual Studio 2015 Preview 中還不支援,但會隨著最終版本釋出。 

9. 更好的 Error List

    Visual Basic 14 的 Error List 有許多實用的改進。在先前的版本,Error List 內的錯誤訊息是顯示完整的類別名稱;現在則是顯示部分類別名稱,錯誤訊息變得更易於閱讀。且會顯示相關的錯誤代碼,可以對錯誤代碼進行排序,甚至可以點選錯誤代碼對該對應的搜尋,也可以針對錯誤代碼進行過濾的動作。

Figure 4 Visual Studio 2015 的 Error List 更易於閱讀與使用

有時候在做些重大的修改時,很容易會將讓連帶用到的程式弄壞。在以往,VB 只會顯示 101 個錯誤。這讓我們很難了解到壞的有多麼嚴重,或是無法總覽必須要做哪些必要的修正。現在,Visual Basic 14 會將所有的錯誤顯示出來 (可以透過 Tools | Options | Text Editor | Basic | Advanced | Show diagnostics for closed files 設定。)

語言的強化

10. Null-Propagating 運算子

    假設有個 Customer 類別,裡面有個 Address 欄位,因為應用程式並未強制使用者輸入,所以可能為 null 值。在以往,任何地方只要需要使用到 address,就必須要作 null 值的檢查,以防止程式出錯。這樣的 null 檢查做起來很快就會感到枯燥乏味了,Visual Basic 14 的 ?. 運算子可以避免這樣的問題: 

 Console.WriteLine("{0} ({1})",   customer.Name,   customer.Address?.Country)

?. 運算子僅僅是一個縮寫,簡化常見且繁瑣的處理,幫我們將值塞給暫存變數,且檢查是否為空: 

 Dim _temp = customer.Address
Console.WriteLine("{0} ({1})",   customer.Name,   If(_temp Is Nothing, Nothing, _temp.Country)) 

你可以串連使用 ?. 運算子,像是 a?.b.c?.d。這樣的程式會由被左到右依序解析處理,當其值為 null,使用的是 ?. 運算子的話,會中斷向下處理,並回傳 Nothing。如果使用的是一般的 . 運算子的話 ,則會丟出 NullReferenceException。

?. 運算子是一 null-conditional 版本的 . 運算子。還有其它 null-conditional 的運算子,像是 索引子 array?(i); 委派叫用 delegate?(args); 字典的查閱 dict?!key。

你也可以將 ?. 用在其它地方: 

 If customer?.Age > 50 Then ...
' customer 不為空且在 50 歲以上時分支
If(customer?.Name, "blank")
'如果 customer 為空則取用預設值
Dim first = customers?.FirstOrDefault()

'叫用方法當 customers 不為空 

11. Multiline String Literals

下面程式表示我們怎樣使用 vbCrLf 去撰寫多行字串: 

 Dim json = "{" & vbCrLf &
"  'Name': 'Bad Boys'," & vbCrLf &
"  'ReleaseDate': '1995-4-7T00:00:00'," & vbCrLf &
"  'Genres': ['Action','Comedy']" & vbCrLf &
"}"

在 Visual Basic中14,您可以:

 Dim json = "{
  'Name': 'Bad Boys',
  'ReleaseDate': '1995-4-7T00:00:00',
  'Genres': ['Action','Comedy']
}" 

現在還可以對多行陳述式進行註解。在以往像下面這樣將註解寫在 LINQ 運算式中是不被允許的: 

 Dim q = From x In y ' This is a from clause
        Where x < z ' And this is the where
        Select x    ' This select is redundant

12. String Interpolation

String interpolation 提供一種較為簡單的方式去撰寫字串運算式,像是: 

 Dim s = $"hello {p.Name} you are {p.Height:0.00}m tall" 

這是下面這段程式的簡寫: 

 Dim s = String.Format("hello {0} you are {1:0.00}m tall", p.Name, p.Height) 

String interpolation 通常較 String.Format 更為容易撰寫,使用上也更為直覺。特別適用於程式化字串,像是:

 Dim fn = $"C:\Documents\{folder}\{file}.{ext}"
Dim url = $"https://{site}/{path}/{file}?search={query}"

注意到這邊,string interpolation 在 Visual Studio 2015 Preview 版本尚未支援,但將會在 Visual Studio 2015 正式釋出的版本開始支援。

13. NameOf 

當我們需要將程式中用到的名稱插入到程式之中,我們可以使用 NameOf 運算子。這邊來看個例子:

 Sub f(s As String)
  If s Is Nothing Then Throw New ArgumentNullException(NameOf(s))
End Sub

NameOf 運算子會在編譯時期解析成常數,而非運行時期才去處理。以這例子來說,這邊的 s 就是一個常數字串。使用 NameOf(s) 可避免不必要的輸入錯誤。舉個例子來說,如果你重新命名方法的參數,NameOf 方法帶入的參數也會自動被更名。如果這邊只是一個寫死的字串的話,是不會有這樣的效果的。NameOf 也可以用在 INotifyPropertyChanged 的實作上: 

 Private _age As Integer
Property Age As Integer
  Get
    Return _age
  End Get
  Set
    _age = Value
    RaiseEvent PropertyChanged(
      Me, New PropertyChangedEventArgs(NameOf(Age)))
  End Set
End Property

注意到這邊,NameOf 在 Visual Studio 2015 Preview 版本尚未支援,但將會在 Visual Studio 2015 正式釋出的版本開始支援。 

14. 開放程式碼

    最後,不是針對 VB 本身的改善,而是針對 VB 流程上的改善。VB 編譯器的程式碼現在是開放的。所以語言的設計過程每個提出的功能都必須要公開審視。微軟 Visual Basic 語言設計團隊基本上會負責管理整個發展。必須要審閱這些提案,深入思考這些提案,看看是否有非預期的陷阱或是意想不到的問題,並決定是否要納入語言之中。令 Visual Basic 語言設計團隊與 VB 的使用者最感到興奮的是,每次語言設計會議的會議紀錄都會被開放出來。 

總結

    Visual Basic 14 帶來很多改進。這邊文章大概只涵蓋了其中的一半。主要都是讓 VB 能更好且更易於使用,沒有引入很難的新概念。欲了解更多信息,請outroslyn.codeplex.com 和 blogs.msdn.com/vbteam。

本文使用搶先版的 Visual Basic 14 與 Visual Studio 2015。所有的資訊隨時可能變動。