共用方式為


匿名類型 (Visual Basic)

Visual Basic 支援匿名類型,可讓您建立物件,而不需撰寫數據類型的類別定義。 相反地,編譯程式會為您產生類別。 類別沒有可用名稱,直接繼承自 Object,並包含您在宣告 物件中指定的屬性。 因為未指定數據類型的名稱,所以稱為 匿名型別

下列範例會將 變數 product 宣告並建立為具有兩個屬性之匿名型別的實例, Name 以及 Price

' Variable product is an instance of a simple anonymous type.
Dim product = New With {Key .Name = "paperclips", .Price = 1.29}

查詢表達式會使用匿名類型來結合查詢所選取數據行。 您無法事先定義結果的類型,因為您無法預測特定查詢可能選取的數據行。 匿名類型可讓您撰寫查詢,以任意順序選取任意數目的數據行。 編譯程式會建立符合指定屬性和指定順序的數據類型。

在下列範例中, products 是產品對象的清單,每個物件都有許多屬性。 namePriceQuery變數會保存查詢的定義,該查詢在執行時,會傳回具有兩個屬性之匿名型別的實例集合,Name以及 Price

Dim namePriceQuery = From prod In products
                     Select prod.Name, prod.Price

nameQuantityQuery變數會保存查詢的定義,該查詢在執行時,會傳回具有兩個屬性之匿名型別的實例集合,Name以及 OnHand

Dim nameQuantityQuery = From prod In products
                        Select prod.Name, prod.OnHand

如需編譯程式針對匿名類型所建立之程式代碼的詳細資訊,請參閱 匿名類型定義

謹慎

匿名型別的名稱是編譯程式所產生的,而且可能會因編譯而異。 您的程式代碼不應該使用或依賴匿名類型的名稱,因為重新編譯專案時名稱可能會變更。

宣告匿名類型

匿名型別實例的宣告會使用初始化表達式清單來指定型別的屬性。 您只能在宣告匿名類型時指定屬性,而不是其他類別專案,例如方法或事件。 在下列範例中, product1 是具有兩個屬性的匿名型別實例: NamePrice

' Variable product1 is an instance of a simple anonymous type.
Dim product1 = New With {.Name = "paperclips", .Price = 1.29}
' -or-
' product2 is an instance of an anonymous type with key properties.
Dim product2 = New With {Key .Name = "paperclips", Key .Price = 1.29}

如果您將屬性指定為鍵屬性,您可以使用它們來比較兩個匿名類型實例相等性。 不過,關鍵屬性的值無法變更。 如需詳細資訊,請參閱本主題稍後的金鑰屬性一節。

請注意,宣告匿名類型的實例,就像使用物件初始化運算式來宣告具名類型的實例一樣。

' Variable product3 is an instance of a class named Product.
Dim product3 = New Product With {.Name = "paperclips", .Price = 1.29}

如需其他指定匿名類型屬性方式的詳細資訊,請參閱 如何:推斷匿名類型宣告中的屬性名稱和類型

索引鍵屬性

主鍵屬性與非主鍵屬性在幾個基本方面有所不同:

  • 只會比較索引鍵屬性的值,以判斷兩個實例是否相等。

  • 關鍵屬性的值是唯讀的,無法變更。

  • 匿名型別的編譯程式產生的哈希程式代碼演算法中只會包含索引鍵屬性值。

平等

匿名型別的實例只有在屬於相同匿名型別時才能相等。 如果兩個實例符合下列條件,則編譯程式會將兩個實例視為相同類型的實例:

  • 它們會在相同的元件中宣告。

  • 其屬性具有相同的名稱、相同的推斷型別,並以相同順序宣告。 名稱比較不區分大小寫。

  • 每個中的相同屬性都會標示為關鍵屬性。

  • 每個宣告中至少有一個屬性是關鍵屬性。

不具有鍵屬性的匿名型別實例只等於本身。

' prod1 and prod2 have no key values.
Dim prod1 = New With {.Name = "paperclips", .Price = 1.29}
Dim prod2 = New With {.Name = "paperclips", .Price = 1.29}

' The following line displays False, because prod1 and prod2 have no
' key properties.
Console.WriteLine(prod1.Equals(prod2))

' The following statement displays True because prod1 is equal to itself.
Console.WriteLine(prod1.Equals(prod1))

如果索引鍵屬性的值相等,則相同匿名類型的兩個實例相等。 下列範例說明如何測試相等。

Dim prod3 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim prod4 = New With {Key .Name = "paperclips", Key .Price = 1.29}
' The following line displays True, because prod3 and prod4 are
' instances of the same anonymous type, and the values of their
' key properties are equal.
Console.WriteLine(prod3.Equals(prod4))

Dim prod5 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim prod6 = New With {Key .Name = "paperclips", Key .Price = 1.29,
                      .OnHand = 423}
' The following line displays False, because prod5 and prod6 do not 
' have the same properties.
Console.WriteLine(prod5.Equals(prod6))

Dim prod7 = New With {Key .Name = "paperclips", Key .Price = 1.29,
                      .OnHand = 24}
Dim prod8 = New With {Key .Name = "paperclips", Key .Price = 1.29,
                      .OnHand = 423}
' The following line displays True, because prod7 and prod8 are
' instances of the same anonymous type, and the values of their
' key properties are equal. The equality check does not compare the
' values of the non-key field.
Console.WriteLine(prod7.Equals(prod8))

Read-Only 值

無法變更索引鍵屬性的值。 例如,在 prod8 上一個範例中, NamePrice 字段是 read-only,但 OnHand 可以變更。

' The following statement will not compile, because Name is a key
' property and its value cannot be changed.
' prod8.Name = "clamps"

' OnHand is not a Key property. Its value can be changed.
prod8.OnHand = 22

來自查詢表達式的匿名型別

查詢表達式不一定需要建立匿名型別。 可能的話,他們會使用現有的類型來存放欄位數據。 當查詢從數據源傳回整個記錄,或每個記錄只傳回一個字段時,就會發生這種情況。 在下列程式代碼範例中, customers 是類別物件的 Customer 集合。 類別有許多屬性,而且您可以依任何順序在查詢結果中包含一或多個屬性。 在前兩個範例中,不需要匿名類型,因為查詢會選取具名類型的元素:

  • custs1 包含字串的集合,因為 cust.Name 是字串。

    Dim custs1 = From cust In customers
                 Select cust.Name
    
  • custs2 包含Customer物件的集合,因為customers的每個元素都是Customer物件,而且查詢會選取整個元素。

    Dim custs2 = From cust In customers
                 Select cust
    

不過,不一定有適當的具名型別可用。 您可能想要針對某個用途選取客戶名稱和位址、另一個用途的客戶標識碼和位置,以及第三個客戶名稱、位址和訂單歷程記錄。 匿名類型可讓您依任何順序選取任何屬性組合,而不需先宣告新的具名類型來保存結果。 相反地,編譯程式會為每個屬性的編譯建立匿名類型。 下列查詢只會從 Customer 中的每個 customers物件中選取客戶的名稱和標識碼。 因此,編譯程式會建立只包含這兩個屬性的匿名型別。

Dim custs3 = From cust In customers
             Select cust.Name, cust.ID

匿名型別中屬性的名稱和資料類型是從 Selectcust.Namecust.ID 的參數取得。 查詢所建立之匿名型別中的屬性一律為鍵值屬性。 在下列 custs3 迴圈中執行 For Each 時,結果是具有兩個主要屬性 NameID 的匿名型別實例集合。

For Each selectedCust In custs3
    Console.WriteLine(selectedCust.ID & ": " & selectedCust.Name)
Next

custs3 表示之集合中的元素是強型別,您可以使用 IntelliSense 巡覽可用的屬性,並驗證其類型。

如需詳細資訊,請參閱 Visual Basic 中的 LINQ 簡介

決定是否要使用匿名類型

在建立物件做為匿名類別的實例之前,請考慮這是否為最佳選項。 例如,如果您想要建立暫存物件來包含相關數據,而且您不需要包含完整類別的其他欄位和方法,則匿名類型是很好的解決方案。 如果您想要針對每個宣告選擇不同的屬性,或想要變更屬性的順序,匿名類型也很方便。 不過,如果您的專案包含數個具有相同屬性的物件,依固定順序,您可以使用具名型別搭配類別建構函式,更輕鬆地宣告它們。 例如,在有適當的建構函式的情況下,宣告 Product 類別的數個實例比宣告數個匿名類型的實例更容易。

' Declaring instances of a named type.
Dim firstProd1 As New Product("paperclips", 1.29)
Dim secondProd1 As New Product("desklamp", 28.99)
Dim thirdProd1 As New Product("stapler", 5.09)

' Declaring instances of an anonymous type.
Dim firstProd2 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim secondProd2 = New With {Key .Name = "desklamp", Key .Price = 28.99}
Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = 5.09}

具名型別的另一個優點是編譯程式可以攔截意外誤用屬性名稱。 在上述範例中, firstProd2secondProd2thirdProd2 是相同的匿名型別實例。 不過,如果您不小心以下列其中一種方式宣告 thirdProd2 ,其類型會與 firstProd2secondProd2的類型不同。

' Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = 5.09}
' Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = "5.09"}
' Dim thirdProd2 = New With {Key .Name = "stapler", .Price = 5.09}

更重要的是,匿名型別的使用有限制,而這些限制不適用於具名型別實例。 firstProd2secondProd2thirdProd2 是相同匿名類型的實例。 不過,共用匿名類型的名稱無法使用,而且無法出現在程式代碼中預期類型名稱的位置。 例如,匿名類型無法用來定義方法簽章、宣告另一個變數或字段,或在任何類型宣告中。 因此,當您必須跨方法共用資訊時,匿名類型並不適用。

匿名類型定義

為了回應匿名型別實例的宣告,編譯程式會建立包含指定屬性的新類別定義。

如果匿名類型包含至少一個索引鍵屬性,則定義會覆寫繼承自Object 的三個成員:EqualsGetHashCodeToString。 為了測試相等性並判斷雜湊碼值,所產生的程式代碼只會考慮重要屬性。 如果匿名類型中沒有索引鍵屬性,則只有ToString會被覆寫。 匿名型別的明確具名屬性不得與這些生成的方法衝突。 也就是說,您無法使用 .Equals.GetHashCode.ToString 來命名屬性。

至少有一個索引鍵屬性的匿名型別定義也會實作System.IEquatable<T>介面,其中T是匿名型別的類型。

如需編譯程式所建立之程式代碼和覆寫方法功能的詳細資訊,請參閱 匿名類型定義

另請參閱