C#中创建匿名类型唯一语法是new { };编译器生成只读、不可继承、无名称的类,属性名和类型由初始化表达式推断,且同一程序集内结构相同的匿名类型视为同一类型。

匿名类型怎么创建:new { } 是唯一语法
C# 中创建匿名类型只有一种方式:用 new { } 对象初始化器,里面写键值对。编译器会自动生成一个只读、不可继承、无名称的类,属性名和类型由初始化表达式推断。
- 属性名必须是合法标识符(不能是数字开头、不能含空格或特殊符号)
- 同一程序集内,若两个
new { A = 1, B = "x" }和new { A = 5, B = "y" }结构完全一致(属性名、顺序、类型相同),它们属于同一个匿名类型;否则就是不同类型 - 所有属性默认为
public get,无法设值(构造后只读)
var person = new { Name = "Alice", Age = 30 };
// 编译后等效于某个自动生成的 class { public string Name { get; } public int Age { get; } }
为什么不能在方法签名里用匿名类型作参数或返回值
匿名类型没有公开类型名,所以不能写在方法声明中。比如下面写法直接报错:
// ❌ 编译失败:CS0029 无法将匿名类型转换为 'object'(除非显式转换)
void Print(new { Name = "", Age = 0 } p) { } // 语法错误,new { } 不是类型
<p>// ✅ 只能用 var 接收,且仅限局部作用域
var x = new { Id = 1, Title = "Test" };
// Print(x); // 即使定义了,调用也失败:找不到匹配的重载</p>
- 函数参数/返回值必须是已知类型(如
object、dynamic或具体类) - 若真要跨方法传递,得转成
object或dynamic,但会丢失编译时类型检查和 IntelliSense
LINQ 查询中匿名类型最常用:select new { } 是核心模式
LINQ to Objects、LINQ to SQL、Entity Framework 的投影(projection)几乎都靠 select new { } 实现轻量数据塑形。它不触发实体映射,也不要求目标类存在。
-
select new { }返回的是IEnumerable(具体是IEnumerable,其中T是编译器生成的匿名类型) - 在 EF Core 中,若查询末尾是
select new { },会生成 SQL 的SELECT col1, col2,不会 SELECT 全字段,有性能优势 - 但注意:EF Core 6+ 要求匿名类型属性必须可被表达式树翻译,不能调用本地方法或使用未映射属性
var result = db.Products
.Where(p => p.Price > 100)
.Select(p => new { p.Id, p.Name, PriceLevel = p.Price > 500 ? "High" : "Medium" })
.ToList(); // ✅ 安全:所有字段都来自数据库列或常量/简单表达式
匿名对象和匿名类型不是一回事:别把 var 当 dynamic
var 是隐式类型局部变量,编译期就确定了真实类型(比如某个匿名类型);而 dynamic 是运行时绑定,完全绕过编译检查。
- 错误认知:“用
var x = new { A = 1 }; x.B = 2;” → 报 CS1061:匿名类型没有B成员,且所有属性只读 - 更隐蔽的坑:把匿名对象传给接受
object的方法后,再试图用反射访问属性——可行,但得用GetProperty,且属性名大小写敏感、无 IntelliSense - 真正需要运行时结构灵活,应考虑
ExpandoObject或 JSON(System.Text.Json.JsonElement),而不是硬啃匿名类型反射
匿名类型本质是编译器糖,用完即弃。一旦离开声明它的作用域,或需要序列化、跨 assembly 传递、动态增删属性,就得换方案。











