本文章是由機器翻譯。

基本技術

在 Visual Basic 2010 集合和陣列初始設定式

Adrian Spotty Bowles

某些語言變更,Microsoft Visual Studio (VS) 2010年產品週期發生有被要略簡化了先前可能只透過使用的大量的重複使用程式碼的工作。 在 Visual Studio 2010 這種方法可以改善用程式碼撰寫經歷讓您更有效率。 在 Visual Studio 2010 發行的新功能是集合初始設定式。 這項功能在 C# 中使用 2008年中,Microsoft 已經被採用一般的同位檢查] 原則的一部分。 一些對 Visual Basic 2010 變更可能會不立即是以明顯,而且這份文件會識別一些較不明顯的實作詳細資料。

集合和陣列是很常見的建構,任何現代的應用中,這些集合通常必須被初始化。 在 2010年的版本才能 Visual Basic 能夠處理某些的限制與基本的陣列初始設定式但集合並不能夠在類似的單行陳述式,通常會導致重複使用程式碼,如下所示的初始化:

Dim x As New List(Of String)
        x.Add("Item1")
        x.Add("Item2")

或它所需建立類別的建構函式,使用類似下列:

Dim x as new list(of string)({"Item1","Item2"})

這種方法都不是特別典雅式解決方案。

雖然兩者他們工作,涉及撰寫額外的程式碼來初始化集合。 雖然這段程式碼通常是簡單的重複使用程式碼,它可以 bloat 來源程式碼可能會導致關聯的維護成本。

如果您透過幾乎任何使用集合的程式碼看起來,您會看到類似的現成的程式碼。 在前面的範例我們要將只有兩個字串的項目中,而使用加入方法的重複呼叫每個字串。 如果我們使用自訂的 「 使用者定義]集合或集合的 「 使用者定義]型別,標準的程式碼會執行相同的工作初始化集合的增加。

新的語法

使用 Visual Studio 2010,我們是現在能夠處理更精簡形式,此集合初始設定工作減少下多個程式碼和重複的新增方法呼叫,將單一陳述式的行:

Dim x As New List(Of String) From {"Item1", "Item2"}

這是簡單範例,以提供型別安全集合架構的一般清單集合型別。 這些集合型別現在是多常用比手動的集合型別實作型別安全集合的過去所使用。

語法允許指定為一份包含在大括號 {} 中,內的項目集合成員,並且每個項目以使用 「 FROM 」 的逗號分隔要判斷正常之前範例的運作方式,是清單型別,但更複雜的集合類型,例如字典,將初始成員 list.The 關鍵字其中可能有索引鍵-值組提供每個成員,我們需要的其他組的每個索引鍵值組,周圍的括號,如下所示:

Dim x As New Dictionary(Of Integer, String)
          From {{1, "Item1"}, {2, "Item2"}}

語法是乾淨且一致。 每個索引鍵值組由巢狀] {},而且是呼叫集合型別 (字典) Add 方法時使用這些引數。 因此上述的線條會等同於:

Dim x As New Dictionary(Of Integer, String)
        x.Add(1, "Item1")
        x.Add(2, "Item2")

實作和其他集合型別中的使用方式

上述範例顯示如何集合初始化一般的架構類型的使用方式。 但是,您可能已實作您自己的集合型別,或可能會希望使用某些型別,您也無法立即使用初始設定式,因為他們缺乏 Add 方法 (範例包含堆疊,佇列)。

若要允許我們在這些情況下使用集合初始設定式功能,很重要稍微了解什麼,涵蓋在進行和如何執行這項功能。 這個瞭解然後會讓我們以展開其使用簡單的清單和字典範例之外。

若要將集合初始設定式語法中,我們需要兩個項目是,則為 True。 型別必須:

  1. 實作此 IEnumerable] 模式可以是任何 IEnumerable 介面,或只是有 GetEnumerator 方法。 這可能被稱為 「 鴨子"輸入:如果它看起來像一個鴨子,並像一個鴨子 quacks,然後可能就是鴨子。
    在我們的案例中如果包含具有一個適當的簽章的 GetEnumerator 方法然後可能其實 IEnumerable 介面類似的行為。 鴨子輸入這樣已經可用來允許型別用於 [每個建構。
  2. 包含至少一個存取 Add 方法,具有一個參數。 這可能是擴充方法或執行個體。

如果您的集合類別符合兩個這些條件,您可以使用集合初始設定式語法。 

集合初始設定式,我們執行不實際使用 IEnumerable 方法來初始化集合,但我們執行將它當做提示判斷這個型別是,在就其實集合型別。 如果它會實作 IEnumerable 或 IEnumerable 模式,然後沒有高可能性,您有一個的集合雖然它不保證。

呼叫新增方法時,每個項目初始設定式清單將項目加入至集合中。 Add 方法是存在的事實並不一定表示它對實作將項目加入至集合的功能。 但使用引數的 Add 方法呼叫轉換從 「 初始化清單"將會進行。

若要說明這點,的圖 1] 下面的程式碼範例有效,並可以使用集合初始設定式的語法但事實上並不會加入至集合的任何項目。

其他的架構類別,使用延伸方法

某些架構集合型別不符合這兩個這些需求。 堆疊和佇列實作方法 (如人口與推入,而非新增。 若要可讓您使用這些型別簡潔集合初始設定式功能,您可以使用延伸方法的能力。 很容易建立這些型別再將允許您初始化簡單的語法與方法的加入擴充方法。

Imports System.Runtime.CompilerServices

Module Module1
    Sub Main()
        Dim st1 As New Stack(Of Integer) From {1, 2, 3}
    End Sub
End Module

Module Extensions
    <Extension()> Sub Add(Of t)(ByVal x As Stack(Of t), ByVal y As t)
        x.Push(y)
    End Sub
End Module

使用 [延伸方法時最好通常延伸只有您控制在型別。 自由使用延伸方法可能導致衝突或行為的變更如果型別升級,因此使用它們時要小心。

使用隱含的行接續符號

Visual Studio 2010 也包含其他許多 awaited 功能:行接續符號。 這項功能可讓您避免麻煩 _] 字元。 這樣就可以將每個項目放在其自己的行,為了清楚起見中在 「 初始化清單 」,項目允許隱含的行接續符號。

Dim st1 As New Stack(Of Integer) From {1,
                                       2,
                                       3}

圖 1 集合初始設定式語法

Module Module1
    Sub Main()
        Dim NC As New TestNonCollectionClass From {1, 2, 3}
    End Sub
End Module

Class TestNonCollectionClass
    Public Function GetEnumerator() As System.Collections.IEnumerator
        'Does Nothing
    End Function

    Public Sub Add(ByVal x As Integer)
        If x = 1 Then
            Console.WriteLine("Add Item" & x.ToString)
        End If
    End Sub
End Class

這可讓您產生很容易閱讀的清除程式碼不包含額外的 _ 字元,並可避免重複。 您可以使用它自己的集合和已經在架構中。 編輯器的 IntelliSense 支援可讓 「 FROM 」支援所有的型別與前述兩個規則,表示它能夠為您的集合型別。 如果您有現有利用為 _ 字元的程式碼,而且想要保留與舊語法一致,仍然支援此選項。

例外狀況處理行為

有一些有趣的 「 初始設定式清單 」 的每個呼叫 Add 方法時指出的項目成員。

就例如時從例外狀況的初始化清單結果 Add 方法以提供的引數呼叫,清單將無法初始化與任何成員。 這表示事實上是集合以所有成員或其不初始化中完全初始化。

這表示如果您的清單中有三個項目,而且呼叫使用例外狀況的 Add 方法結果時,第三個,您會得到擲回例外狀況和一個未初始化的集合。 followingexample 刻意產生例外狀況來示範這個實際的案例,並產生 「 空白 」正在寫入主控台。 但是,變更初始設定式清單] 移除三個值將會導致"Initialized: 項目計數 2"如的圖 2] 所示。

圖 2 變更初始設定式清單

Imports System.Runtime.CompilerServices

Module Module1
    Sub Main()
        Dim l1 As Stack(Of Integer)
        Try
            l1 = New Stack(Of Integer) From {1, 2}
        Catch ex As Exception
        End Try
        If l1 Is Nothing Then
            Console.WriteLine("Blank")
        Else
            Console.WriteLine("Initialized - Element Count:" & l1.Count)
        End If
    End Sub
End Module

Module Extensions
    <Extension()> Sub Add(Of t)(ByVal x As Stack(Of t), ByVal y As t)
        If y.ToString = "3" Then
            Throw New Exception("Intentional Exception")
        Else
            x.Push(y)
        End If
    End Sub
End Module

如果這不會發生,它可能需要製作其他程式碼,判斷是否沒有初始設定例外狀況發生和狀態為何集合時。

若要縮短語法使用延伸方法

標準的語法,來初始化一組複雜的物件集合,導致不必重複 [新增 < 型別 >每個初始設定式清單中項目。

Module Module1
    Sub Main()
        Dim CustomerList As New List(Of Customer)
        From {New Customer With {.Name = "Spotty", .Age = 39},
              New Customer With {.Name = "Karen", .Age = 37}}
    End Sub
End Module

Class Customer
    Public Property Name As String = ""
    Public Property Age As Integer = 0
End Class

語法需要在初始設定式清單每個項目具現化。 透過副檔名的方法的使用很可能以縮短仍然進一步此語法。 功能是依賴集合型別支援 IEnumerable 介面,而且也有 Add 方法將會導致被封入類別初始設定式清單項目被對應到新增的方法參數,以示的圖 3

圖 3 使用延伸方法

Imports System.Runtime.CompilerServices

Module Module1
    Sub Main()
        'Shortend Syntax through the use of extension methods
        Dim CustomerList As New List(Of Customer) 
          From {{"Spotty", 39}, {"Karen", 37}}

    End Sub
End Module

Module Extension
    <Extension()> Public Sub add(ByVal x As List(Of Customer), _
      ByVal Name As String, ByVal Age As Integer)
        x.add(New Customer With {.Name = Name, .Age = Age})
    End Sub
End Module

Class Customer
    Public Property Name As String = ""
    Public Property Age As Integer = 0
End Class

新增方法多載

新增方法條件非常重要這個功能,且可被多載。 每一種方法會呼叫它自己根據呼叫的引數的多載。 這裡沒有魔法,而且新增方法多載解析的運作方式就像多載解析的任何方法的運作方式。

這一次是最佳示範一個簡單的範例。 的圖 4,我們有不同的資料型別多載,我們會呼叫一個適用於呼叫的引數。

為什麼 FROM' 語法使用和不 '='?

此功能要求產品小組的一個常見的問題,是使用 「 FROM 」關鍵字,因為陣列初始設定式已經使用"="工作分派。

在 Visual Basic,可具現化集合類別,以三個不同的方式:

Dim x1 As New List(Of Integer)
        Dim x2 = New List(Of Integer)
        Dim x3 As List(Of Integer) = New List(Of Integer)

加入這兩個語法的執行個體化集合已經包含的是 = 在語法中的字元。 使用其他 = 字元會導致混淆,在語法中的集合型別的新執行個體的工作分派和成員的初始化之間至集合。

使用關鍵字,而非一個 = 字元來決定集合初始設定式動作的結果可以避免這個問題,並允許所有現有語法慣例來宣告和初始化集合型別的型別。 還要判斷在初始設定式清單,方法仍然很熟悉現有的陣列初始設定式語法。

FROM 關鍵字之後多討論選擇。 到那些熟悉使用 LINQ 查詢,似乎很奇怪選擇因為已經有用於 LINQ FROM 關鍵字。 它可能會出現這個選項可能會導致潛在的語意模糊 LINQ 查詢中使用時,但我們將會看到,「 這是不大小寫。

沒有 'FROM'可能與 'FROM' 用法相衝突在查詢嗎?

甚至在包含集合初始設定式的查詢沒有關鍵字的模稜兩可。 這可以是下列程式碼所示範:

Module Module1
    Sub Main()
        'The first from is the query,
        'the second is the collection initializer.
        'The parser can always successfully identify the difference
        Dim x = From i In New List(Of Integer) From {1, 2, 3, 4}
                Where i <= 3
                Select i
        For Each i In x
            Console.WriteLine(i)
        Next
        Stop
    End Sub
End Module

物件初始設定式中使用集合 Initalizer 的限制

2008年的產品 Visual Basic 小組實作啟用初始化物件欄位屬性,當它們被執行個體化物件執行個體時,開發人員物件初始設定式:

Dim x As New List(Of Integer) With {.Capacity = 10}

不過,它並不能初始化物件和在相同的宣告集合,因此下列會產生語法錯誤:

Dim x as New List(Of Integer) from {1,2,3} With {.Capacity = 10}

有一些其他較不明顯變更發生在 2010年與相關的可能不是立即明顯,但有影響的程式碼使用陣列的陣列。

圖 4 對不同的資料類型的多載

Imports System.Runtime.CompilerServices

Module Module1
    Sub Main()
        Dim l1 As New Stack(Of Integer) From {1, 2.2, "3"}
        Console.WriteLine("Element Count:" & l1.Count)
        Stop
    End Sub
End Module

Module Extensions
    <Extension()> Sub Add(ByVal X1 As Stack(Of Integer), _
      ByVal x2 As Integer)
        Console.WriteLine("Integer Add")
        X1.Push(x2)
    End Sub
    <Extension()> Sub Add(ByVal X1 As Stack(Of Integer), _
      ByVal x2 As Double)
        Console.WriteLine("Double Add")
        X1.Push(CInt(x2))
    End Sub
    <Extension()> Sub Add(ByVal X1 As Stack(Of Integer), _
      ByVal x2 As String)
        Console.WriteLine("String Add")
        X1.Push(CInt(x2))
    End Sub
End Module

陣列初始設定式變更

雖然才能 2010年版本是可以初始化簡單陣列,沒有仍有些限制。 其中一個最近的變更可以讓陣列型別初始化,並推斷更簡潔的方式。

先前,來識別在 Visual Basic 做為陣列中的項目需要您指定識別項上的一組的括號:

Dim a() As Integer = {1, 2, 3}

現在並不需要這些括號,並型別會被推斷為陣列型別與選項推斷在導致更簡潔的語法:

Dim a = {1, 2, 3}

陣列型別推斷

在 2008,已實作該型別推斷功能的啟用資料型別推斷其工作分派的值。 此方法的屍體內宣告的單一物件但陣列並不會推斷型別,因此是永遠的物件陣列。

Sub Main()
        Dim a() = {1, 2, 3}
          'Type would previously result in Object Array prior to 2010
    End Sub

這已經過改良,並現在陣列型別會被推斷,如下所示:

Sub Main()
        Dim a = {1, 2, 3} 'Type now infers Integer Array
    End Sub

陣列的推斷的型別取決在 2008年中,加入主控項的型別功能。 這個型別推斷仍然僅適用的程式碼以便欄位會仍然是物件陣列,除非特別輸入宣告內方法的屍體。

它可以初始化多個的陣列維度,但是所有巢狀的組必須包含相同數目的成員。 因此維度的兩個範例將使用。

下列兩個範例同時會建立一個二維的整數陣列:

Dim TwoDimension1(,) = {{1, 2}, {3, 4}}
        Dim TwoDimension2 = {{1, 2}, {3, 4}}

為一維陣列,語法的類似前述的程式碼,以及所有現有的程式碼會繼續使用少數的例外狀況]。

Dim a() = {1, 2, 3}

在前面的陳述式將推斷陣列型別初始設定式清單中。 這將導致所推斷的整數陣列。 在過去,這些只是本來應該是物件陣列,我們不會有推斷初始設定式清單中的任何陣列型別。 如果您使用任何的檢查類型、 使用反映,或包含多個多載,包括物件陣列型別程式碼,這現在可能會產生不同的結果。 這可能包括晚期繫結方法。

多維陣列

讓您初始化多維陣列維度必須符合在初始設定式清單中的項目計數。 如果這些不是相同,並且初始化清單中所有的巢狀項目並沒有一致的項目計數然後則語法會發生錯誤:

Dim TwoDimension2 = {{1, 2}, {3, 4}}
  'Valid 2 dimension integer(,) array inferred
Dim TwoDimension2Invalid(,) = {{1}, {3}}
  'Invalid – dimension and element count mismatch
Dim TwoDimension2Invalid1(,) = {{1, 2}, {3}}
  'Invalid:element count not consistent in Initializer List

這表示前,可能會使用類似的語法來初始化標準固定維度的陣列。

不規則的陣列初始設定

但是,這表示為不規則陣列 (陣列的陣列),此語法不會運作時。 若要允許的不規則的陣列初始設定式,就需要您的 [成員] 清單中每個括號中進行包裝:

Sub Main()
        'Incorrect Jagged Array syntax
        Dim JaggedDimensionIncorrect()() = {{1,2},{3,4,5}}

        'Correct Jagged Array syntax
        Dim JaggedDimension1()() = {({1,2}),({3,4,5})}
    End Sub

前面的範例會產生所示:

  • 包含的項目 1,2 的整數陣列的 JaggedDimension1(0)
  • 包含的項目 3,4,5 的整數陣列的 JaggedDimension1(1)

陣列型別推斷會用於巢狀的陣列型別。 以下是一個稍微複雜的範例:

Dim JaggedDimension1() = {({1, 2}), ({3.1, 4.2, 5.3})}

這將導致 JaggedDimension1 被推斷為 Object() 和成員的型別 Integer() 被和 Double()。

陣列推斷和預期的行為

所以您查看初始設定式清單做為推斷的陣列。 不! 在初始設定式清單不是實體類型,您可能會認為 ;它是語法表示成員,清單使其成為特定類型,它用在內容而定。

下列程式碼範例示範我們可以使用 {,、,} 語法:

1.推斷並初始化整數陣列:

Dim a = {1, 2, 3}  'Infers Integer Array

這適用於指定沒有目標型別,它會推測出根據主控項的初始設定式清單成員型別,而其型別。

2. 初始化不同型別的陣列:

Dim b As Single() = {1, 2, 3}
  'Will convert each integer value into single

如我們會初始化一個陣列值,第一張、 兩個和第三,這將會運作。 在初始設定式清單有沒有內建的型別。 本身

但是,下列預期會失敗:

Dim a = {1, 2, 3}  'Infers Integer()
        Dim c As Single() =
          a 'No conversion between Single() and Integer()

這似乎有點奇怪但變數將是被推斷為整數陣列,以第一張、 兩個和第三的值初始化。 變數 c 被宣告為單一的陣列。 但是,沒有單一的陣列和整數陣列將會造成語法錯誤之間的轉換。

獨立陣列初始設定式使用

陣列初始設定式清單也可以用在獨立的內容中它在這種情況下將具有不具有指定的目標型別,而將做為主控項的型別成員的初始化清單的陣列。

這可讓一些有趣的案例先前無法使用。 範例可能是您要用來初始化資料結構的項目陣列中的方法。 呼叫此方法會決定不同的預設值作為呼叫的引數的圖 5 所示。

在這種情況下我們建立陣列本機每個呼叫,只是將陣列型別傳遞至方法。 使用新的獨立使用功能,仍可避免建立不必要的區域變數,這種案例,並只可以使用獨立初始設定式清單將陣列型別]。

在獨立的使用案例中,初始設定清單會貼齊推斷的陣列型別。 因此在獨立的使用情況下初始化清單可以視為陣列常值。 這樣可以節省不必宣告只會用於例如個別方法呼叫的限制執行個體中的項目。

圖 5 不同的預設值,當作呼叫引數

Module Module1

    Sub InitializeMethod(ByVal x As String())
        '....
    End Sub

    Sub Main()
        Dim i As Integer = 1

        Select Case I
            Case 1
                Dim Array1 As String() = {"Item1", "Item2"}
                InitializeMethod(Array1)
            Case 2
                Dim Array1 As String() = {"Item11", "Item12"}
                InitializeMethod(Array1)
        End Select
    End Sub
End Module

使用其他 2010年功能

2010 版本產品的功能是多重目標。 雖然這項功能會存在於 2008年版本,一些增強功能所做的許多語言功能允許在 2010年版本的產品用於下為目標的版本中 (2.0,3.0 和 3.5 目標)。 因此,您可以使用這項改良的功能集合和陣列初始設定式您現有的應用程式如果要使用 2010年版本的產品。 這可讓您簡化您現有的原始程式碼,並利用新的語言功能。

因此當您使用 [這項新功能是否有潛在的破壞現有程式碼? 該問題的答案是,有回溯相容性符號,一些可能但這是限制在幾個案例優點超過原始的中斷變更而可以輕易地保留現有的功能:

Dim x1() = {1, 2, 3}

在舊的版本前的一行程式碼會造成 Object 陣列,但與 Visual Studio 2010,這將會為主控項的項目型別推斷型別,在這種情況下 Integer()。 這會是大小寫,不論是否您的目標 4.0] 或 [向下目標到較早版本。 如果您有需要特定類型的物件陣列的程式碼,這段程式碼可能會失敗。 它可以輕易地藉由明確指定目標型別更正:

Dim x1() As Object = {1, 2, 3}

這個行為的例外狀況是當沒有主控項的類型的項目:

Dim x1() = {1, 2.2, "test"}

這會保留先前的行為,導致 x 1 物件陣列。

簡單的應用程式

集合初始設定式是一個很棒除了語言。 它們允許更簡潔的語法,以初始化架構和使用者定義的集合型別。 以最少的變更這個語法可以套用到現有的程式碼輕鬆。

功能是語法的適合能夠使用其他語言功能,例如啟用任何集合型別所使用的降低的擴充方法。 較小且更容易維護,在先前使用的重複使用程式碼中此減少使程式碼。

導致實作陣列型別推斷] 和 [允許的陣列的獨立使用方式的改良的功能,以及改善能夠在前一個版本上初始化多維和不規則陣列,陣列初始設定式行為已稍微,進行變更。

幾乎每個應用程式使用陣列,或集合與這項功能可用於幾乎任何專案。

Adrian Spotty Bowles 已使用每個版本的 Visual Basic 開發而且已找到台北市,Wash.他方法,他在工作位於 Visual Basic 產品小組的軟體設計工程師軟體測試人員著重於 Visual Basic 編譯器。 在 Visual Basic 2008 發行,他投入的許多語言功能,包括副檔名 Methods.You 可以到達 Bowles 在的 Abowles@microsoft.com]。