Visual Basic 14新語法 - 2

by vivid 6. 四月 2016 13:17

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

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

部分模組(Partial modules)

部分模組(Partial modules)允許你將一個模組的程式碼,定義在兩個不同的檔案之中,在編譯階段,編譯器會自動將兩個檔案中模組的程式碼,合併成一個完整的模組。

例如以下在Module2.vb檔案中包含以下程式,利用partial 關鍵字定義Module1模組,其中定義一個ShowMessage方法:

Partial Module Module1
  Public Sub ShowMessage()
    Console.WriteLine("Hello " & name)
  End Sub
End Module

 

在Module1.vb檔案中包含以下程式,利用partial 關鍵字定義Module1模組,其中定義一個name變數:

 

Partial Module Module1
  Dim name As String = "mary"
  Sub Main()
    ShowMessage()
  End Sub

End Module


程式編譯之後,我們利用ildasm.exe工具來檢視它的描述資訊,你可以很清楚地看到,兩個模組的內容被合併成一個完整模組,包含name變數與ShowMessage方法,請參考下圖所示:

clip_image002

圖 1:編譯階段將合併部份模組成完整模組。

部分介面(Partial interfaces)

部分介面(Partial interfaces)允許你將一個介面的程式碼,定義在兩個不同的檔案之中,在編譯階段,編譯器會自動將兩個檔案中介面的程式碼,合併成一個完整的介面定義。

舉例來說,Module1.vb檔案中包含以下程式,利用partial 關鍵字定義IShape介面,其中定義一個Perimeter方法:

Partial Interface IShape
  Function Perimeter() As Integer
End Interface

Module2.vb檔案中包含以下程式,利用partial 關鍵字定義IShape介面,其中定義一個Area方法:

Partial Interface IShape
  Function Area() As Integer
End Interface

程式編譯之後,我們利用ildasm.exe工具來檢視組件的描述資訊,你可以很清楚地看到,兩個介面的內容被合併成一個完整介面,包含Perimeter與Area方法,請參考下圖所示:

clip_image004

圖 2:編譯階段將合併部份介面成完整介面。

以年起始的日期字串(Year-first Date Literals)

Visual Basic現在可以定義年起始的日期字串(Year-first date literals)了,你可以使用「/」或「-」符號來當做日期分隔字串,以下這四種寫法都將日期設定為2016年2月3日:

Dim mydate As Date = #2016/2/3#

Console.WriteLine(mydate) '2016/2/3 上午 12:00:00

mydate = #2-3-2016#

Console.WriteLine(mydate) '2016/2/3 上午 12:00:00

mydate = #2-3-2016#

Console.WriteLine(mydate) '2016/2/3 上午 12:00:00

mydate = #2016-2-3#

Console.WriteLine(mydate) '2016/2/3 上午 12:00:00

另外時間的部分,可以指定12小時制,或是24小時制,以下使用格式化字串,顯示時間的範例:

mydate = #2016-2-3 1:2:30 PM#

Console.WriteLine(mydate.ToString("yyyy/MM/dd tt HH:mm:ss ")) '2016/02/03 下午 13:02:30

Console.WriteLine(mydate.ToString("yyyy/MM/dd tt hh:mm:ss ")) '2016/02/03 下午 01:02:30

在隱含接續程式加註解(Comments after implicit line continuation)

若程式碼太長,Visual Basic可以使用行接續字元(line-continuation sequence),即「_」號,將程式換行來顯示。而Visual Basic也支援隱含行接續(Implicit Line Continuation)功能,將陳述式接續到下一個連續行而不必使用底線字元 「_」來串接。現在,在隱含行接續程式的後方,可以加上註解了,特別適合在撰寫LINQ運算式的情況下,例如以下的範例程式碼:

Module Module1

  Private courses As New List(Of Course)() From {
  New Course() With {
    .Id = 1,
    .Name = "MVC"
  },
  New Course() With {
    .Id = 2,
    .Name = "WebForm"
  },
  New Course() With {
  .Id = 3,
  .Name = "WebAPI"
  }
  }

  Sub Main()
    Dim list = From c In courses    'From List
               Where c.Name.StartsWith("Web") 'check start with "Web"
               Select c   'return course

    For Each c In list
      Console.WriteLine(c.Name)
    Next
  End Sub

End Module

Public Class Course
  Public Property Id() As Integer
  Public Property Name() As String
End Class

TypeOf <expr> IsNot <type>

在過去IsNot 運算子不能用來比較從 TypeOf 運算子傳回的運算式,而得要改用 Not 和 Is 運算子。現在已支援,參考以下範例程式碼,判斷變數的型別是否為Employee型別:

Module Module1
  Sub Main()
    Dim x As New Sales
    If TypeOf x IsNot Employee Then
      Console.WriteLine("Not Employee")
    Else
      Console.WriteLine("Employee")
    End If
  End Sub

End Module
Public Class Employee

End Class
Public Class Sales
  Inherits Employee
End Class

 

智慧名詞解析(Smarter Fully-qualified Name Resolution)

Visual Basic編輯器提供新的智慧名詞解析功能,我們以實例來說明這個功能。以下範例程式碼,在Main方法的第一行,使用到MySystem.HR命名空間下的MyClassA類別;而第二行則使用到MyTesting命名空間下的MyClassB類別。

 

Imports VB14Lang.MySystem
Imports VB14Lang.MyTesting

Module Module1
  Sub Main()
    HR.MyClassA.PrintMsg()
    HR.MyClassB.PrintMsg()
  End Sub

End Module

Namespace MySystem
  Namespace HR
    Public Class MyClassA
      Public Shared Sub PrintMsg()
        Console.WriteLine("A")
      End Sub
    End Class
  End Namespace
End Namespace

Namespace MyTesting
  Namespace HR
    Public Class MyClassB
      Public Shared Sub PrintMsg()
        Console.WriteLine("B")
      End Sub
    End Class
  End Namespace
End Namespace


智慧名詞解析(Smart name resolution)會合併所有引用的命名空間進行比對,找出想用的成員。在撰寫程式碼的過程中,Visual Studio 的智慧型提示功能(IntelliSense)也會適當地進行提示,讓你自由選取想使用的是MySystem.HR命名空間下的MyClassA類別,請參考下圖所示:

clip_image006

圖 3:使用智慧名詞解析。

還是MyTesting命名空間下的MyClassB類別,請參考下圖所示:

clip_image008

圖 4:智慧名詞解析。

唯讀的介面屬性(Readonly Interface Properties)

類別的可讀寫屬性,可以實作唯讀介面屬性,那麼直接來看程式碼吧:

Interface INotify
  ReadOnly Property Msg As String
End Interface

Class MyTestClass
  Implements INotify
  Dim data As String
  Public Property Msg As String Implements INotify.Msg
    Get
      Return data
    End Get
    Set(value As String)
      data = value
    End Set
  End Property
End Class
Module Module1
  Sub Main()
    Dim c As New MyTestClass()
    c.Msg = "Hello"
    Console.WriteLine(c.Msg)
  End Sub

End Module

 

在方法中使用#Region(#Region inside methods)

#Region 主要的功能是在程式中折疊程式碼,C#很早以前就有這樣的功能,而Visual Basic到此版本才提供,可以在方法之中,使用#Regin來折疊程式碼:

Module Module1
  Sub Main()
#Region "CreateObject"
    Dim c As New MyTestClass()
    c.Msg = "Hello"
    Console.WriteLine(c.Msg)
#End Region
  End Sub
End Module

折疊程式碼的結果,請參考下圖所示:

clip_image010

圖 5:折疊程式碼。

其它語法

最後這個小節之中,就回顧一下Visual Basic已有,而C#到第6版才支援的語法。

引用靜態成員(Static imports)

若使用Imports語法引用命名空間,如此使用到此命名空間的類別就不用寫全名,例如以下程式,引用System之後,就可以直接使用Console類別,叫用它的方法:

Imports System
Module Module1
  Sub Main()
    Console.WriteLine("Hello")
  End Sub

End Module


Imports語法,可以引用到類別,我們將上列的程式碼改寫如下,在程式檔案上方,使用Imports關鍵字,引用到System.Console類別,後續程式碼就可以直接叫用Console類別的WriteLine方法,使得程式碼更為精簡:

 

Imports System
Module Module1
  Sub Main()
    Console.WriteLine("Hello")
  End Sub

End Module


 

在撰寫程式時,有很多常用的類別都可以比照辦理,像是DateTime、Math類別等等,例如以下程式碼片段引用了常用的Console、DateTime、Math類別等等:

Imports System.Console
Imports System.Math
Module Module1
  Sub Main()
    WriteLine("Hello")
    WriteLine(Now)
    WriteLine(PI)
  End Sub
End Module

當然使用此語法時要適當的自行處理不同命名空間下,有相同類別名稱的命名衝突問題。例如以下程式碼在A與B兩個命名空間下,都包含一個MyClass類別,其中有一個Print()方法,若同時使用using static語法引用到A與B命名空間,則在Main方法叫用到Print()方法時,這段程式碼將不能編譯:

Imports VB14Lang.B.MyTestClass
Imports VB14Lang.A.MyTestClass
Module Module1
  Sub Main()
    PrintMsg()
  End Sub
End Module

Namespace A
  Public Class MyTestClass
    Public Shared Sub PrintMsg()
      Console.WriteLine("A")
    End Sub
  End Class
End Namespace

Namespace B
  Public Class MyTestClass
    Public Shared Sub PrintMsg()
      Console.WriteLine("B")
    End Sub
  End Class
End Namespace


編譯的錯誤訊息如下:

Error BC30561 'PrintMsg' is ambiguous, imported from the namespaces or types 'VB14Lang.B.MyTestClass, VB14Lang.A.MyTestClass'

編譯結果,請參考下圖所示:

clip_image012

圖 6:命名衝突錯誤。

Exception Filters

C# 6版才提供Exception Filters語法,而這個語法Visual Basic早就有了。在此回顧一下語法,當你使用try..catch語法攔截例外錯誤時,可以在catch區段搭配 when關鍵字,設定篩選條件,以篩選要攔截的例外錯誤,參考以下程式碼範例:

Module Module1
  Sub Main()
    Dim i As Integer = 0
    Try
      Dim k As Integer = Integer.Parse("x")
      Dim j As Integer = 10 / i
    Catch ex As Exception When ex.Message = "Input string was not in a correct format."
      Console.WriteLine("Format Error")
    Catch ex As Exception When ex.Message = "Arithmetic operation resulted in an overflow."
      Console.WriteLine("Overflow")
    End Try
  End Sub
End Module

 

自動屬性初始設定式 (Auto-Properties Initializers)

這也是舊版Visual Basic就有的功能,C# 6版才支援。若要為自動屬性設定值,我們可以額外撰寫一些程式碼,例如透過建構函式來初始化自動屬性的值。參考以下範例程式碼,Employee類別中包含ID、Name兩個自動屬性,在建構函式中,設定它們的值:

Module Module1
  Sub Main()
    Dim emp = New Employee(1, "Mary")
    Console.WriteLine(emp.ID) '1
    Console.WriteLine(emp.Name) 'Mary
  End Sub
End Module
Class Employee
  Public Sub New()
  End Sub
  Public Sub New(empId As Integer, empName As String)
    ID = empId
    Name = empName
  End Sub
  Public Property ID() As Integer
  Public Property Name() As String
End Class

你也可以在使用自動屬性語法時,可以宣告順帶初始化屬性的值,只要宣告時加上「=」等號,再給個值就行了,參考以下範例程式碼:

Module Module1
  Sub Main()
    Dim emp = New Employee()
    Console.WriteLine(emp.ID) '1
    Console.WriteLine(emp.Name) 'Mary
  End Sub
End Module
Class Employee
  Public Property ID() As Integer = 1
  Public Property Name() As String = "Mary"
End Class

C#才支援的語法

最後這幾個是僅C#才支援的語法,Visual Basic不支援:

  • Expression-bodied member
  • Index initializer
  • 在 catch/finally 使用Await

Tags:

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

新增評論




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






NET Magazine國際中文電子雜誌

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

月分類Month List