匿名类型提供了一种简便的方法,可将一组只读属性封装到单个对象中,而无需先定义命名类型。 编译器在编译时生成类型名称,无法在源代码中访问。 编译器推断每个属性的类型。
将 new 运算符与对象初始值设定项结合使用来创建匿名类型。 以下示例显示了使用两个属性初始化的匿名类型, Name 以及 Age:
var person = new { Name = "Alice", Age = 30 };
Console.WriteLine($"{person.Name} is {person.Age} years old.");
// Output:
// Alice is 30 years old.
推断的属性名称
可以使用 Name = value 语法显式指定属性名称。 使用变量或成员访问表达式初始化匿名类型时,编译器会从该表达式推断属性名称:
string productName = "Laptop";
decimal price = 999.99m;
var product = new { productName, price };
Console.WriteLine($"{product.productName}: {product.price:C}");
// Output:
// Laptop: $999.99
在前面的示例中,编译器从初始值设定项中使用的变量名称推断 productName 和 price 属性名称。
使用 var 声明匿名类型
由于编译器生成类型名称,并且无法在源代码中访问它,因此必须使用 var 它来声明局部变量。 无法显式指定类型名称:
// You must use var — you can't write a named type here.
var person = new { Name = "Alice", Age = 30 };
在 LINQ 查询中使用匿名类型
匿名类型最常出现在查询表达式的子句中 select ,其中投影每个源元素的属性子集:
var words = new[] { "apple", "blueberry", "cherry" };
var results = words.Select(w => new { Word = w, Length = w.Length });
foreach (var item in results)
{
Console.WriteLine($"{item.Word} has {item.Length} letters.");
}
// Output:
// apple has 5 letters.
// blueberry has 9 letters.
// cherry has 6 letters.
平等
具有相同属性名称和类型的两个匿名类型实例共享相同的编译器生成的类型。 编译器重写Equals和GetHashCode,以便在相等性比较中比较属性值,而不是引用标识。
var a = new { Name = "Alice", Age = 30 };
var b = new { Name = "Alice", Age = 30 };
var c = new { Name = "Bob", Age = 25 };
Console.WriteLine(a.Equals(b)); // True
Console.WriteLine(a.Equals(c)); // False
嵌套匿名类型
匿名类型可以包含其他匿名类型作为属性值:
var order = new
{
OrderId = 1,
Customer = new { Name = "Alice", City = "Seattle" },
Total = 150.00m
};
Console.WriteLine($"Order {order.OrderId} for {order.Customer.Name} in {order.Customer.City}");
// Output:
// Order 1 for Alice in Seattle
特征
匿名类型具有以下特征:
- 编译器生成它们作为
internal sealed class派生自 Object的类型。 - 所有属性都是
public只读的。 - 匿名类型支持
with非破坏性突变的表达式。 - 编译器生成基于值的Equals、GetHashCode和ToString重写。
- 匿名类型支持 表达式树,而元组则不支持。
局限性
匿名类型有几个限制:
- 不能将它们用作方法返回类型、方法参数或字段类型,因为无法命名类型。
- 它们的作用域限定在声明它们的方法内。
- 不能添加方法、事件或自定义运算符。
- 属性始终为只读;匿名类型不支持可变属性。
何时改用元组
对于大多数新代码,请考虑使用 元组 而不是匿名类型。 作为值类型,元组可提供更好的性能。 它们还提供析构支持和更灵活的语法。 如果需要表达式树支持或引用类型语义,匿名类型仍然是更好的选择。 有关详细比较,请参阅 在匿名类型和元组类型之间进行选择。