匿名型別

匿名類型提供一個便利的方法,將一組唯讀屬性封裝成一個物件,而不需要事先明確定義類型。 類型名稱會由編譯器產生,並且無法在原始程式碼層級使用。 每個屬性的類型會由編譯器推斷。

您可以搭配物件初始設定式使用 new 運算子,來建立匿名型別。 如需物件初始設定式的詳細資訊,請參閱物件和集合初始設定式

下列範例顯示以兩個名為 AmountMessage 的屬性初始化的匿名類型。

var v = new { Amount = 108, Message = "Hello" };

// Rest the mouse pointer over v.Amount and v.Message in the following
// statement to verify that their inferred types are int and string.
Console.WriteLine(v.Amount + v.Message);

您通常可以在查詢運算式的 select 子句中使用匿名型別,以從來源序列中的每個物件傳回屬性子集。 如需查詢的詳細資訊,請參閱 LINQ in C#

匿名類型包含一個或多個公用唯讀屬性。 其他類型的類別成員 (例如方法或事件) 則無效。 用於初始化屬性的運算式不可以是 null、匿名函式或指標類型。

最常見的情況是使用其他類型的屬性來初始化匿名類型。 下列範例假設存在一個名為 Product 的類別。 Product 類別包含 ColorPrice 屬性,以及您不感興趣的其他屬性。 變數 productsProduct 物件的集合。 匿名類型宣告的開頭為 new 關鍵字。 宣告會初始化新類型,只使用 Product 中的兩個屬性。 使用匿名型別會使查詢中傳回較小的資料量。

如果未在匿名類型中指定成員名稱,編譯器會為匿名類型成員指定與用於初始化類型之屬性相同的名稱。 您為以運算式初始化的屬性提供一個名稱,如上述範例所示。 在下列範例中,匿名類型的屬性名稱是 ColorPrice

var productQuery =
    from prod in products
    select new { prod.Color, prod.Price };

foreach (var v in productQuery)
{
    Console.WriteLine("Color={0}, Price={1}", v.Color, v.Price);
}

提示

您可以使用 .NET 樣式規則 IDE0037 來強制執行推斷或明確成員名稱。

您也可以依另一種型別的物件定義欄位:類別、結構,甚至是另一個匿名型別。 做法是使用保存此物件的變數,就像在下列範例中一樣,使用已具現化的使用者定義型別建立兩個匿名型別。 在這兩種情況下,product 匿名型別shipmentshipmentWithBonus 中的欄位都會是型別 Product,其中包含每個欄位的預設值。 而且 bonus 欄位會是編譯器所建立的匿名型別。

var product = new Product();
var bonus = new { note = "You won!" };
var shipment = new { address = "Nowhere St.", product };
var shipmentWithBonus = new { address = "Somewhere St.", product, bonus };

一般而言,當您使用匿名型別初始化變數時,您可以使用 var 將變數宣告為隱含型別區域變數。 由於只有編譯器可以存取匿名類型的基本名稱,因此無法在變數宣告中指定類型名稱。 如需 var 的詳細資訊,請參閱隱含類型區域變數

您可以如下列範例所示,合併隱含類型區域變數和隱含類型陣列,以建立匿名類型項目的陣列。

var anonArray = new[] { new { name = "apple", diam = 4 }, new { name = "grape", diam = 1 }};

匿名型別是直接衍生自 objectclass 型別,並且無法轉換成 object 以外之任何類型的類型。 編譯器提供每種匿名類型的名稱,不過您的應用程式無法存取此名稱。 對 Common Language Runtime 來說,匿名類型與其他任何參考類型並無不同。

如果組件中有兩個或多個匿名物件初始設定式,指定了順序相同並具有相同名稱和類型的屬性序列,編譯器會將這些物件視為相同類型的執行個體。 這些物件會共用編譯器產生的相同類型資訊。

匿名型別會搭配運算式的形式支援非破壞性變化。 這可讓您建立匿名型別的新執行個體,其中一或多個屬性具有新的值:

var apple = new { Item = "apples", Price = 1.35 };
var onSale = apple with { Price = 0.79 };
Console.WriteLine(apple);
Console.WriteLine(onSale);

您無法將欄位、屬性、事件或方法的傳回類型,宣告為具有匿名類型。 同樣地,您無法將方法、屬性、建構函式或索引子的型式參數宣告為具有匿名類型。 若要以方法引數的形式來傳遞匿名類型或含有匿名類型的集合,您可以將參數宣告為 object 類型。 不過,針對匿名型別使用 object 會破壞強型別的目的。 如果您必須在方法界限外儲存或傳遞查詢結果,請考慮使用一般具名結構或類別來取代匿名類型。

由於匿名類型上的 EqualsGetHashCode 方法會以屬性的 EqualsGetHashCode 方法來定義,相同匿名類型的兩個執行個體僅在其所有屬性都相等時,這兩個執行個體才相等。

注意

匿名型別的存取層級internal,因此在不同組件中定義的兩個匿名型別不是相同類型。 因此,在不同組件中定義時,匿名型別的執行個體不能彼此相等,即使其所有屬性都相等也一樣。

匿名型別會覆寫 ToString 方法,並串連以大括弧括住的每個屬性名稱和 ToString 輸出。

var v = new { Title = "Hello", Age = 24 };

Console.WriteLine(v.ToString()); // "{ Title = Hello, Age = 24 }"