匿名型別 (C# 程式設計手冊)
匿名型別提供便利的方式將唯讀屬性集封裝至單一物件,而不必先明確定義型別。 型別名稱是由編譯器產生,而且在來源程式碼層級中無法使用。 每個屬性的型別是由編譯器推斷。
您可以使用 new 運算子搭配物件初始設定式來建立匿名型別。 如需物件初始設定式的詳細資訊,請參閱物件和集合初始設定式 (C# 程式設計手冊)。
下列範例示範透過名為 Amount 和 Message 的兩個屬性所初始化的匿名型別。
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 查詢運算式 (C# 程式設計手冊)。
匿名型別包含一個或多個公用唯讀屬性。 沒有任何其他類型的類別成員 (例如方法或事件) 是有效的。 用來初始化屬性的運算式不可以是 null、匿名函式或指標型別。
最常見的情節是使用其他型別的屬性初始化匿名型別。 下列範例假定有一個名為 Product 的類別存在。 類別 Product 包含 Color 和 Price 屬性,以及您不會感興趣的其他屬性。 變數 products 是 Product 物件的集合。 匿名型別宣告是以 new 關鍵字開頭。 宣告會初始化一個新的類型,此類型只使用兩個來自 Product 的屬性。 這會使查詢只傳回更少量的資料。
如果您未指定匿名型別中的成員名稱,編譯器會提供匿名型別成員與要對其進行初始化之屬性相同的名稱。 您必須提供名稱給要以運算式初始化的屬性,如上一個範例所示。 在下列範例中,匿名型別的屬性名稱為 Color 和 Price。
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);
}
當您使用匿名型別初始化變數時,通常會使用 var 將變數宣告為隱含型別區域變數。 因為只有編譯器可以存取匿名型別的基礎名稱,所以無法在變數宣告中指定型別名稱。 如需 var 的詳細資訊,請參閱 隱含型別區域變數 (C# 程式設計手冊)。
您可以結合隱含型別區域變數和隱含陣列,以建立匿名型別元素的陣列,如下列範例所示。
var anonArray = new[] { new { name = "apple", diam = 4 }, new { name = "grape", diam = 1 }};
備註
匿名型別是直接衍生自 物件,因此,無法轉換為 物件以外的任何型別的 類別 型別。 雖然您的應用程式不能存取它,但編譯器為每個匿名型別提供了名稱。 從 Common Language Runtime 的角度來看,匿名型別與其他參考型別不同。
如果在組件的兩個以上的匿名物件初始設定式指定順序,並具有相同的名稱和型別屬性的序列,編譯器會將物件視為相同型別的執行個體。 它們會共用編譯器產生的相同型別資訊。
您無法將欄位、屬性、事件或方法傳回型別宣告為具有匿名型別。 同樣地,您不能宣告有匿名型別之方法、屬性、建構函式或索引子的正式參數。 若要傳遞匿名型別或包含匿名型別的集合做為方法的引數,您可以將參數宣告為 object 型別。 但是,這樣做失去強型別的目的。 如果您必須在方法界限外儲存或傳遞查詢結果,請考慮使用一般的具名結構或類別,而不使用匿名型別。
因為匿名型別上的 Equals 和 GetHashCode 方法是根據屬性的 Equals 和 GetHashcode 方法定義,相同匿名型別的兩個執行個體只有在其所有屬性都相等時才會相等。