在處理臨時資料結構、LINQ 查詢投影或跨層資料傳遞時,我們常需要一種「只有形狀、無關型別名稱」的輕量物件。C# 3.0 引入的匿名類型完美解決此問題,讓開發者無須定義正式類別即可擁有強型別、IntelliSense 支援的物件。
搭配 var 與物件初始化器語法:
// 建立匿名類型實例
var book = new { Name = "C# 3.0", Price = 100 };
// 存取屬性(唯讀)
Console.WriteLine(book.Name); // C# 3.0
Console.WriteLine(book.Price); // 100
// 編譯錯誤:匿名類型屬性預設為唯讀
// book.Name = "New Name";
若來源物件已有同名屬性,可直接投射:
public class Book { public string Name { get; set; } public decimal Price { get; set; } }
Book source = new Book { Name = "C# in Depth", Price = 45.9m };
var projected = new { source.Name, source.Price }; // 屬性名自動推斷
關鍵規則: 在同一組件中,屬性名稱、型別、宣告順序完全相同的匿名類型,編譯器會產生單一共享型別。因此:
var a = new { Name = "A", Price = 10 };
var b = new { Name = "B", Price = 20 };
var c = new { Price = 10, Name = "A" }; // 順序不同 -> 不同型別
a = b; // 合法:同一型別
// a = c; // 編譯錯誤:型別不同
匿名類型覆寫了 Equals、GetHashCode、ToString,以所有屬性值為基礎進行值相等比較,適合作為 LINQ 分組鍵或字典鍵值。
匿名類型為參考型別,繼承自 object,但型別名稱僅存在於編譯期,執行期為編譯器生成的不可讀名稱(如 <>f__AnonymousType0<string, int>)。
跨方法傳遞限制:
object 或 dynamic 傳遞,導致強型別屬性存取喪失。Tuple/ValueTuple。| 概念 | 說明 | 範例 |
|---|---|---|
隱式型別區域變數 (var) | 編譯器依初始化運算式推斷變數型別,變數本身仍有具體型別 | var i = 10; // int |
| 匿名類型 | 編譯器依初始化器建立新型別並產生實例,型別無名稱 | var o = new { X = 1 }; // 型別為匿名類型 |
兩者常搭配使用:var o = new { ... } 中,var 推斷變數型別為編譯器產生的匿名類型。
select new { ... })