Visual Basic 14新語法 - 1

by vivid 23. 三月 2016 13:08

.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號:N160316902
出刊日期:2016/3/23
開發工具:Visual Studio 2015 Update 1
版本:.NET Framework 4.6、Visual Basic 14

在這一個系列的文章之中,我將介紹Visual Basic程式語言所提供的新功能,這篇文章是第一篇,你可以參考第一篇「Visual Basic 14新語法 - 2」文章,來了解更多新語法。若想要了解C# 6的新語法,請參考「C# 6 新語法 – 1」與「C# 6 新語法 – 2」兩篇文章。

Visual Studio 2015工具提供的新功能

在Visual Basic專案中,Visual Studio工具提供許多新的功能,像是程式碼重構(Refactor),舉例來說,若有Visual Basic 主控台程式如下:

Module Module1

  Sub Main()
    Dim i As Integer = 10
    Dim j As Integer = 20

    Dim r As Integer = i + j
  End Sub

End Module

 

若反白選取「i + j」這段程式碼,然後按下「CTRL + .」組合鍵,此時就會啟動「Quick Action」功能,Visual Studio 2015程式視窗便會出現一個燈泡,當你點選它,Visual Studio 2015會提示您是否進行必要的程式修訂動作,例如,是否重構,將選取的程式碼抽取出來,包裝成方法,請參考下圖所示:

clip_image002

圖 1:使用程式碼重構(Refactor)。

當你選取「Extract Method」選項,工具便會自動修訂程式碼如下:

Module Module1

  Sub Main()
    Dim i As Integer = 10
    Dim j As Integer = 20

    Dim r As Integer = GetR(i, j)
  End Sub

  Private Function GetR (i As Integer, j As Integer) As Integer
    Return i + j
  End Function
End Module

 

並且跳出一個視窗,顯示是否變更方法的名稱,你可以直接編輯名稱,請參考下圖所示:

clip_image004

圖 2:程式碼重構(Refactor),變更變數名稱。

甚至在程式碼輸入錯誤時,也會自動顯示「Quick Action」,提示是否修訂程式碼,請參考下圖所示:

clip_image006

圖 3:「Quick Action」提示是否修訂程式碼。

Null-conditional operators

在Visual Basic程式中若使用到Nothing物件進行轉型或某些邏輯判斷動作,可能會產生例外,導致程式無法順利執行,例如以下程式碼中定義一個Employee型別變數,初始化為Nothing,但下一行程式碼就使用到Employee型別的EmpName屬性:

Module Module1
  Sub Main()

    Dim emp As Employee = Nothing
    Console.WriteLine(emp.EmpName)
  End Sub

End Module
Class Employee
  Public EmpName As String
End Class


執行時,在上述的Console.WriteLine那行程式碼會因使用到未配置記憶體的物件,而產生例外錯誤,訊息請參考下圖所示:

clip_image008

圖 4:NullReferenceException錯誤。

我們需要在程式中進行判斷,在emp變數不為Nothing的情況下,才存取Employee類別的EmpName屬性,修改程式碼如下:

Module Module1
  Sub Main()

    Dim emp As Employee = Nothing
    If emp IsNot Nothing Then
      Console.WriteLine(emp.EmpName)
    End If
  End Sub

End Module
Class Employee
  Public EmpName As String
End Class

 

在Visual Basic中可以使用  Null Conditional Operator 來解決這個問題,不必再自己判斷變數是否為Nothing,修改上面程式如下,只要一行程式碼,搭配成員存取運算子「?.」,就可以判斷Nothing問題,再執行程式就不會有例外錯誤:

 

Module Module1
  Sub Main()

    Dim emp As Employee = Nothing
    Console.WriteLine(emp?.EmpName)
  End Sub

End Module
Class Employee
  Public EmpName As String
End Class

 

此外我們也可以搭配if( ) 運算子一起使用,在變數為Nothing時,直接設定預設值,改寫上例程式碼如下:

 

Module Module1
  Sub Main()

    Dim emp As Employee = Nothing
    Dim r = If(emp?.EmpName, "NoName")
    Console.WriteLine(r)
  End Sub

End Module
Class Employee
  Public EmpName As String
End Class


 

執行後,當emp為Nothing時,便會印出預設值「NoName」,程式執行結果,請參考下圖所示:

clip_image010

圖 5:使用Null-conditional operators。

Null Conditional Operator 可以搭配事件的語法,來檢查事件是否被註冊,若事件已註冊,再觸發事件,在前一版你需撰寫類似以下if的語法:

Module Module1
  Sub Main()
    Dim btn = New MyButton()
    AddHandler btn.Click, Sub(sender, e)
                            Console.WriteLine("Btn Click")
                          End Sub
    btn.OnClick(EventArgs.Empty)

  End Sub

End Module
Class MyButton
  Public Event Click As System.EventHandler
  Public Sub OnClick(e As EventArgs)
    If ClickEvent IsNot Nothing Then
      RaiseEvent Click(Me, e)
    End If
  End Sub
End Class

 

範例中的MyButton類別包含一個Click事件,而onClick方法中判斷是否此事件被其它物件註冊,若有,才觸發Click事件。另外注意,事件的名稱為Click,而Visual Basic編譯器會建立一個private變數,命名規則是以事件名稱串接「Event」字串,代表事件。在程式中判斷ClickEvent是否為Nothing便可知道事件是否被註冊。除了使用RaiseEvent關鍵字觸發事件之外,也可以改用Call關鍵字,例如可以將上述程式碼改寫如下:

Module Module1
  Sub Main()
    Dim btn = New MyButton()
    AddHandler btn.Click, Sub(sender, e)
                            Console.WriteLine("Btn Click")
                          End Sub
    btn.OnClick(EventArgs.Empty)

  End Sub

End Module
Class MyButton
  Public Event Click As System.EventHandler
  Public Sub OnClick(e As EventArgs)
    If ClickEvent IsNot Nothing Then
      Call ClickEvent(Me, e)
    End If
  End Sub
End Class

 

現在Visual Basic 14可以這樣寫,改用「?.」判斷事件是否註冊,然後利用Invoke方法觸發事件:

Module Module1
  Sub Main()
    Dim btn = New MyButton()
    AddHandler btn.Click, Sub(sender, e)
                            Console.WriteLine("Btn Click")
                          End Sub
    btn.OnClick(EventArgs.Empty)

  End Sub

End Module
Class MyButton
  Public Event Click As System.EventHandler
  Public Sub OnClick(e As EventArgs)
    ClickEvent?.Invoke(Me, e)
  End Sub
End Class

 

此範例的執行結果如下圖所示:

clip_image012

圖 6:觸發事件。

字串格式化(String interpolation)

在前版Visual Basic,若要格式化字串,常常使用到字串參數,例如以下字串中的{0}代表第一個參數,{1}代表第二個參數:

"Now is {0}:{1}"

以主控台程式為例,我們可以使用以下程式碼進行字串格式化,WriteLine方法的第二個參數值會代入{0}參數;而,WriteLine方法的第三個參數值會代入{1}參數:

Module Module1
  Sub Main()
    Dim h = DateTime.Now.Hour
    Dim m = DateTime.Now.Minute
    Console.WriteLine("Now is {0}:{1}", h, m) 'Now is 5:57
  End Sub
End Module

 

現在在Visual Basic 14之中,你可以直接在參數中引用變數的值,只要在字串前方加上 「$」符號,就可以使用到 h與m變數,並把h與m變數的值,直接代入{h}與{m}參數:

 

Module Module1
  Sub Main()
    Dim h = DateTime.Now.Hour
    Dim m = DateTime.Now.Minute
    Console.WriteLine($"Now is {h}:{m}") 'Now is 5:57
  End Sub
End Module

 

此外也可以自訂顯示格式,例如以下程式碼,不足兩位數時前方將自動補「0」:

 

Module Module1
  Sub Main()
    Dim h = DateTime.Now.Hour
    Dim m = DateTime.Now.Minute
    Console.WriteLine($"Now is {h:00}:{m:00}") 'Now is 5:57
  End Sub
End Module

 

而以下的範例程式碼,展示貨幣的格式化語法,新的語法讓使用字串格式化的動作變得更為簡單:

Module Module1
  Sub Main()
    Dim money As Double = 12345.67
    Console.WriteLine($"Money is {money:c}") 'Money is $12,345.67
    Console.WriteLine($"Money is {money:#,###.000}") 'Money is 12,345.670
  End Sub
End Module

 

唯讀自動屬性(Read-only auto-properties)

在Visual Basic舊版,自動屬性一定是可讀寫的,以下程式碼片段是舊版Visual Basic的自動屬性語法,Company類別中包含一個Name的自動屬性,它們是可讀寫屬性:

 

Module Module1
  Sub Main()
    Dim p As New Company()
    p.Name = "MyCompany"
    Console.WriteLine(p.Name)
  End Sub
  Class Company
    Public Property Name() As String
  End Class
End Module

 

在Visual Basic 14允許設計唯讀自動屬性,並利用 Auto-Properties Initializers 進行初始化,改寫上述範例程式碼如下:

Module Module1
  Sub Main()
    Dim p As New Company()
    Console.WriteLine(p.Name)
  End Sub
  Class Company
    Public ReadOnly Property Name() As String = "MyCompany"
  End Class
End Module

 

同時也可和唯讀變數一樣,你可以在建構函式之中進行初始化的動作:

Module Module1
  Sub Main()
    Dim p As New Company("MyCompany")
    Console.WriteLine(p.Name)
  End Sub
  Class Company
    Public Sub New(n As String)
      Name = n
    End Sub
    Public ReadOnly Property Name() As String
  End Class
End Module

 

除了在建構函式之中可以修改唯讀屬性的值之外,不能夠在其他程式碼試圖修改它的值,Visual Studio 2015 將會提示錯誤,請參考下圖所示:

clip_image014

圖 7:不能夠在其他程式碼試圖修改它的值。

nameof運算子

有時程式執行發生例外錯誤,我們想要提醒程式設計師錯誤是來自於一個參數,以便於程式除錯,如以下程式碼所示,在開啟檔案時,若發生找不到檔案的例外錯誤,在訊息中將提示fileName參數設定有誤:

Imports System.IO

Module Module1
  Sub Main()
    OpenFile("c:\temp\b.txt")
  End Sub

  Private Sub OpenFile(fileName As String)
    If Not File.Exists(fileName) Then
      Throw New FileNotFoundException("File Not Found! check fileName parameter", fileName)
    Else
      Dim s = File.ReadAllText(fileName)
      Console.WriteLine(s)
    End If
  End Sub
End Module

 

程式在執行時若發生例外,將顯示以下的錯誤訊息:

Unhandled Exception: System.IO.FileNotFoundException: File Not Found! check fileName parameter

參考執行結果如下圖:

clip_image016

圖 8:執行例外。

萬一有一天程式碼因進行最佳化或程式重構的關係,fileName變數名稱被改掉了,而例外錯誤訊息中忘了更改,此時印出的訊息就牛頭不對馬嘴,程式中並不存在一個fileName參數:

Imports System.IO

Module Module1
  Sub Main()
    OpenFile("c:\temp\b.txt")
  End Sub

  Private Sub OpenFile(fs As String)
    If Not File.Exists(fs) Then
      Throw New FileNotFoundException("File Not Found! check fileName parameter", fs)
    Else
      Dim s = File.ReadAllText(fs)
      Console.WriteLine(s)
    End If
  End Sub
End Module

 

為了避免這種情況,我們可以利用nameof運算子來取得變數的名稱,例如改寫程式碼如下:

 

Imports System.IO

Module Module1
  Sub Main()
    OpenFile("c:\temp\b.txt")
  End Sub

  Private Sub OpenFile(fileName As String)
    If Not File.Exists(fileName) Then
      Throw New FileNotFoundException("File Not Found! check " _
      & NameOf(fileName) & " parameter", fileName)
    Else
      Dim s = File.ReadAllText(fileName)
      Console.WriteLine(s)
    End If
  End Sub
End Module

 

得到的錯誤訊息如下:

Unhandled Exception: System.IO.FileNotFoundException: File Not Found! check file

Name parameter

但若修改變數名稱為fs如下:

Imports System.IO

Module Module1
  Sub Main()
    OpenFile("c:\temp\b.txt")
  End Sub

  Private Sub OpenFile(fs As String)
    If Not File.Exists(fs) Then
      Throw New FileNotFoundException("File Not Found! check " _
      & NameOf(fs) & " parameter", fs)
    Else
      Dim s = File.ReadAllText(fs)
      Console.WriteLine(s)
    End If
  End Sub
End Module

 

得到的錯誤訊息能正確地反應錯誤的參數為何:

Unhandled Exception: System.IO.FileNotFoundException: File Not Found! check fs parameter

同樣的,我們也可以搭配字串格式化的新語法來輸出錯誤訊息:

Imports System.IO

Module Module1
  Sub Main()
    OpenFile("c:\temp\b.txt")
  End Sub

  Private Sub OpenFile(fileName As String)
    If Not File.Exists(fileName) Then
      Throw New FileNotFoundException($"File Not Found! check {NameOf(fileName)} parameter.")
    Else
      Dim s = File.ReadAllText(fileName)
      Console.WriteLine(s)
    End If
  End Sub
End Module

多行文字輸入(Multiline string literals)

在前版Visual Basic,當文字內容有多行時,你需要利用字串串接方式,將多行文字的內容整合在一起,例如以下範例,使用了多行的SQL查詢語法:

Module Module1
  Sub Main()
    Dim sql As String = "select * " & vbCrLf &
    "From Stores " & vbCrLf &
    "Where stor_id = 1 "
    Console.WriteLine(sql)
  End Sub
End Module

在Visual Basic 14,字串內容可以多行顯示,程式可以改寫如下:

Module Module1
  Sub Main()
    Dim sql As String = "select *
       from Stores
       Where stor_id = 1 "
    Console.WriteLine(sql)
  End Sub
End Module

Tags:

.NET Magazine國際中文電子雜誌 | Visual Studio | 許薰尹Vivid Hsu | Visual Basic

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List