共用方式為


匿名類型 (Visual Basic)

Visual Basic 支援匿名型別,其可讓您在建立物件時,不需要撰寫資料類型的類別定義。 編譯器 (Compiler) 會自動幫您建立類別 (Class)。 該類別沒有可使用的名稱,直接繼承自 Object,但是包含您在宣告物件時指定的屬性。 因為未指定資料類型的名稱,所以稱為「匿名型別」

下列範例會宣告和建立變數 product 作為匿名型別執行個體,其具有下列兩個屬性:NamePrice

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

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

在下列範例中,products 是產品物件的清單,每個物件都有許多屬性。 變數 namePriceQuery 保有查詢的定義,當查詢執行時,會傳回匿名型別執行個體的集合,其具有下列兩個屬性:NamePrice

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

變數 nameQuantityQuery 保有查詢的定義,當其執行時,會傳回匿名型別執行個體的集合,其具有下列兩個屬性:NameOnHand

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}

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

索引鍵內容

索引鍵屬性與非索引鍵屬性具有下列數種基本上的差異:

  • 僅會比較索引鍵屬性的值,以判斷兩個執行個體是否相等。

  • 索引鍵屬性的值為唯讀,且無法變更。

  • 匿名型別的編譯器所產生雜湊碼演算法中,只會包含索引鍵屬性值。

Equality

只有在匿名型別的執行個體是相同匿名型別的執行個體時,它們才能相等。 如果兩個執行個體符合下列條件,則編譯器會將兩個執行個體視為相同類型的執行個體:

  • 在相同的組件中宣告。

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

  • 每個執行個體中的相同屬性都標示為索引鍵屬性。

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

沒有索引鍵屬性的匿名型別執行個體只等於其本身。

' 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))

唯讀值

您無法變更索引鍵屬性的值。 例如,在先前範例的 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

查詢運算式的匿名型別

查詢運算式不一定需要建立匿名型別。 可能的話,查詢運算式會使用現有的類型來保存資料行資料。 當查詢從資料來源傳回完整記錄,或每個記錄只傳回一個欄位時,就會發生這種情況。 在下列程式碼範例中,customersCustomer 類別的物件集合。 類別有許多屬性,且您可以依任何順序在查詢結果中包含一或多個屬性。 在前兩個範例中,因為查詢會選取具名類型的元素,所以不需要匿名型別:

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

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

    Dim custs2 = From cust In customers
                 Select cust
    

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

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

匿名型別中屬性的名稱和資料類型都是從引數擷取至 Selectcust.Namecust.ID。 查詢所建立匿名型別中的屬性,一律為索引鍵屬性。 在下列 For Each 迴圈中執行 custs3 時,結果是匿名型別的執行個體集合,其中包含兩個索引鍵屬性: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 是該匿名型別的類型。

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

另請參閱