Visual Basic 14的語言特性

jopen 9年前發布 | 8K 次閱讀 Visual Basic

與Visual Studio類似,Visual Basic也將從版本12直接跳到14。雖然新版本中的許多特性對于C#來說也是首次引進,但仍然有大量的功能增強是特別針對VB的,旨在簡化VB的使用。本文列舉了一些最令我們感興趣的特性。

對Null的支持

新版本的一個特性是對null值的支持,該特性使用?.操作符。這一特性與C#相同,如果操作符左方的表達式返回值不為null,則繼續計算右方表達式。在處理外部資源所返回的少量數據時,該特性尤其有用。舉例來說:

If customer.PrimaryResidence IsNot Nothing AndAlso customer.PrimaryResidence.Garage IsNot Nothing AndAlso property.PrimaryResidence.Garage.Cars = 2 Then Print("Two Car Garage")

這段代碼將被簡化成以下語句:

If property.PrimaryResidence?.Garage?.Cars = 2 Then Print("Two Car Garage")

除此之外,還可以將該操作符與If操作符進行結合,實現為表達式提供某個默認值的功能:

Dim numberOfCarPorts = If(property.PrimaryResidence?.Garage?.Cars, 0)

C#與VB并不是唯一兩種支持這種null處理方式的語言。在Apple的產品中得到廣泛應用的Objective-C語言默認就支持該行為。尤其是它的方法調用也使用.操作符,其工作方式就類似于VB中的?.操作符。

在Objective-C的社區中,人們對該特性的評價褒貶不一。某些開發者非常喜愛這項功能,因為他們在進行方法調用時無需擔心空引用異常的產 生。而另一些開發者則對此感到痛恨,因為在問題發生時,他們不會看到空引用異常的產生,只會看到方法調用失敗。如此一來他們就會感到困惑,為什么方法返回 了null,而不是返回有效值或拋出異常。

元編程

在Visual Basic 12中,我們首次看到了CallerNameAttribute這一特性的引入。雖然這一特性解決了屬性變更通知(property change notification)的問題,但它的通用性還不足以解決另外一部分問題,在這些問題中需要一個以字符串形式表達的唯一標識符,在這種情況下,需要使 用到NameOf這個操作符。

以下這個示例是由來自Visual Basic團隊的Lucian Wischik所提供的,其中包括對參數進行驗證的邏輯。

Function Lookup(name As String) As Customer

If name is Nothing Then Throw New ArgumentNullException(NameOf(name))</pre>

這種方式能夠避免在修改了參數名稱的時候,忘記修改了所拋出異常的構造函數中所定義的字符串。由于NameOf操作符實際上創建了一個常量,因此你可以在任何需要使用硬編碼字符串的時候使用該操作符。

字符串插值(Interpolation)

自從十年以前.NET初次問世的時候,String.Format這個方法就要求開發者們對參數的數量進行計數。多年以來,由于計數錯誤所產生的bug可謂是不計其數。字符串插值這一技術最初是由Mono團隊為C#語言所創建的,它徹底解決了計數這種糟糕的做法。

插值字符串是由$”開頭的,而不是單單使用”。對于每個你需要插入值的位置,都要使用一對大括號進行轉義,這一點與String.Format的做 法是相同的。另一個與String.Format相同的地方在于可以在轉義中加入格式化選項。在下面這個簡單的示例中出現了兩個變量,name和 total,后者將被格式化為貨幣格式。

Dim message = $"Hello {name}, your amount due is {total:C2}"

該語法本身就使用了String.Format方法,因此使用者同樣需要注意在適當的場合進行轉義,考慮一下以下字符串:

Dim requestUrl = $"http://{server}/customer?name={customerName}"

這段代碼會產生一個bug,開發者實際上需要的是以下代碼:

Dim requestUrl = $"http://{server}/customer?name={UrlEncode(customerName)}"

FormattedString對象

乍一看插值字符串的語法,似乎無法處理從外部資源中獲取字符串的場景,例如從本地化表或資源字典中獲取字符串。不過,微軟正在努力實現這一功能。Lucian Wischik寫道:

不僅能夠使用在不同的語言文化中,而且還能夠從中抽取出原始的格式化字符串或者是參數(舉例來說,如果你打算在SQL查詢中使用該語法,或者會需要對參數進行轉義,以避免產生字符串注入攻擊)。但目前為止,我們還沒有完全決定該語法的設計規格。

按照當前的規格聲明草稿所說,插值字符串可以是一個常規的字符串,也可以由一個名為FormattedString的對象實現。當你試圖將某個插值字符串賦值給一個實現了IFormattable接口的變量或是參數時,系統會自動創建一個FormattedString類型的實例。

該對象的IFormattable.ToString方法接受一個類型為IFormatProvider類型的參數,使用該參數能夠重寫格式化相關的行為。

string IFormattable.ToString(string ignored, IFormatProvider formatProvider)
        {
            return String.Format(formatProvider, format, args);
        }

在上面一段代碼中,format與args兩個參數分別代表了待插值的原始字符串,以及它所對應的值。

多行字符串

在VB中新加入的一個特性是多行字符串。實現它不需要任何特殊的語法,只需要在希望分行的地方省略引號即可。根據源代碼文件所使用的換行符的不同, 該換行符會自動在vbCrlf、vbCr及vbLf等符號間進行選擇。對于Visual Studio的用戶來說,基本上都會選擇vbCrlf。

在目前,某些開發者會選擇在XML文本中使用CData段落來模仿這一特性,這種方式雖然能夠實現所需要的效果,但顯得有些冗長與笨拙。

屬性

自動屬性現在可以標記為只讀了。可以在聲明時為該屬性賦值,也可在構造函數中進行賦值。

該語法的使用方式應該不會出乎你的意料:

Public ReadOnly FirstName As String = "Anonymous"
Public ReadOnly LastName As String
Public Sub New (firstName As String, lastName As String)
    Me.FirstName = firstName
    Me.LastName = lastName
End Sub

在使用這一特性時,應當考慮到某些特殊情況。要理解這些情況,你首先必須理解參數傳遞的copy-in和copy-out概念。CLR只允許你為變量及字段進行引用傳遞(即C#中的ref或out操作符)。但在VB中,你也能夠為屬性進行引用傳遞。

為了緩解這兩者之間的分歧,VB會在準備進行函數調用時創建一個本地變量,該屬性的值會被拷貝到這個本地變量中。該本地變量隨后被傳遞至函數中,函數體能夠修改該本地變量的值。當該函數返回時,本地變量的值會拷貝回屬性中。

在使用只讀的自動屬性時,將會應用以下規則:

  1. 如果你在構造函數中的某個lambda表達式中使用只讀自動屬性,編譯器會提示語法錯誤。
  2. 如果在構造函數或初始化器中使用只讀自動屬性,將應用copy-in與copy-out規則。Copy-out操作會將值寫入系統為屬性生成的字段中。
  3. 如果不在構造函數或初始化器中使用只讀自動屬性,則只會應用copy-in規則。Copy-out操作根本不會發生,但也不會產生任何語法錯誤。

這些規則都是基于只讀字段的工作原理所產生的。

注釋

現在,在一個多行語句的每一行末尾都可以加入注釋了。在之前的版本中,只能在多行語句的最后一行末尾加入注釋。請看以下示例:

Dim emailList = 
    From c in Customers
    Where c.IsActive 'ignore inactive customers
    And Not c.DoNotEmail 'we don’t need another spam violation
    Select c.FullName, c.EmailAddress

結構體

結構體現在能夠支持無參構造函數了。雖然CLR本身就支持這一特性,但還沒有主流的編程語言實現了這一特性,其原因是構造函數的運行時機并不明確。舉例來說,在創建某個結構體的數組時,該結構體的構造函數并不會運行。

如果你的代碼是myStruct = new MyStructure(),那很顯然該構造函數會立即執行。而如果你的代碼是myStruct = Nothing,則顯然不會執行構造函數。但在某個本地變量或成員變量自動初始化時又是否會執行構造函數呢?無論你選擇哪一種答案,總會讓一部分人感覺不 爽。

數據文本(Data Literals)

從今年開始,數據文本(對于JSON格式來說非常重要的一個特性)終于改為使用符合ISO標準的格式了。在過去,數據文本一直使用基于美國的格式化形式,對于居住在歐洲的人來說就會產生一些迷惑。

  • 老風格:#3/4/2005#(是三月四日,還是四月三日?)
  • 新風格:#2005-4-3#

與C#的互操作性

Overrides修飾符將會隱含使用Overloads修飾符。在過去,VB的開發者必須同時使用這兩種修飾符,才能保證C#的使用者在使用由VB所創建的類庫時能夠調用正確的重載方法。

接口模糊性

在C#中使用接口繼承這一特性時,會造成不易判斷到底是哪個接口方法被調用的問題。在VB中不允許出現這種場景,但由于C#允許這一特性,會造成出現某些VB無法實現的接口的情況。(在Microsoft Dynamics的某個產品中就數次出現這種情況。)

相對于C#中所使用的“通過名稱隱藏”(hide-by-name)的重載規則,VB 14中將對這一限制進行放寬,轉而使用一種(對VB來說)更傳統的方式,即“通過簽名隱藏”的規則。

命名空間解析

VB也曾在命名空間解析這一問題上栽過跟斗,考慮一下以下代碼:

Threading.Thread.Sleep(1000)

按Lucian Wischik所說:

之前,VB會嘗試查找“Threading”這一命名空間,由于它無法分辨System.Threading和 System.Windows.Threading的區別,因此直接報錯。現在,VB14會同時支持這兩種可能匹配的命名空間。如果你在代碼編輯器輸入 Threading.,那么在輸入.號之后,你會在智能提示中看到對這兩個命名空間的支持。

類似的情況還有許多,舉例來說:在編寫Winforms應用時,ComponentModel.INotifyPropertyChanged事件 就會無法分辨System.ComponentModel及System.Windows.Forms.ComponentModel,這一問題如今將不 復存在。

TypeOf和IsNot

微軟在十年前就創建了IsNot操作符,自那以來,就不斷有VB的開發者要求微軟允許在TypeOf表達式中使用IsNot操作符,舉例如下:

If TypeOf sender IsNot Button Then

預處理指令

VB 14為預處理指令提供了兩點改進之處。

Regi7on

Region將能夠在函數體中進行使用,甚至是跨兩個函數體進行使用。

關閉警告

與C#相同,Visual Basic現在也能夠關閉對某一個代碼塊的編譯警告了。在規格說明中提供了一個示例:

#Disable Warning BC42356 'suppress warning about no awaits in this method

通常來說,開發者會通過某個指令在該代碼文件的其它地方重新打開這一警告

#Enable Warning BC42356

如果該警告的ID中包含了空格或標點符號,則必須使用引號。微軟的工具不會自動為你完成這一點,不過由Roslyn所編寫的第三方分析器規則或許能實現這一點。

VB的快速修復(Quick Fix)特性能夠通過自動添加這些指令實現繞過某些警告的目的。這一點對于之前提到的第三方分析器規則來說尤其有用,因為你不一定能夠很快地找到對應的ID。

XML文檔驗證

目前來說,VB編譯器會忽略XML文檔的內容。而在VB 14中,編譯器就會試圖在文檔中查找錯誤,例如不正確的參數引用名稱。它還能夠“正確地處理crefs標簽中的泛型與操作符”。

部分模塊(partial module)與接口聲明

與類和結構體類型,你現在能夠將模塊與接口聲明為部分(partial)了。通常來說,這一特性是為代碼生成器所準備的,但也能夠在跨多個平臺分享代碼時發揮作用。

關于作者

Visual Basic 14的語言特性 Jonathan Allen的 第一份工作是在二十世紀90年代后期時,參與某個醫療診所的管理信息系統項目的開發,將該項目由Access及Excel逐漸轉化為企業級解決方案。隨 后,當他為某個商業部門的自動交易系統工作了五年之后,他決定轉為進行高端用戶界面的開發。在空余時間,他喜歡閱讀及撰寫一些關于西方武術在15世紀至 17世紀之間發展的文章。

 

查看英文原文:Article: Visual Basic 14 Language Features

來自:http://www.infoq.com/cn/articles/VB-14

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!