C#匿名类型的用法(附带实例)
C# 中的匿名类型是一个由编译器临时创建的类,它用于存储一组值。
如果需要创建一个匿名类型,则可以使用 new 关键字,随后使用对象初始化器来指定该类型包含的属性和值。例如:
匿名类型的属性名称可以从一个本身为标识符(或者以标识符结尾)的表达式推断得到,例如:
在同一个程序集内声明的两个匿名类型实例,如果它们的元素名称和类型是相同的,那么它们在内部就是相同的类型:
此外,匿名类型还会重写 Equals 方法来执行结构化相等比较(即数据值的比较):
以下代码创建了一个匿名类型的数组:
匿名类型的对象无法通过方法有效地返回,因为将函数返回类型指定为 var 是非法的:
匿名类型是不可更改的,因此匿名类型的实例在创建之后无法进行改动。但是,在 C# 10 中,可以使用 with 关键字创建一个可变更的副本(非破坏性更改)。
如果需要创建一个匿名类型,则可以使用 new 关键字,随后使用对象初始化器来指定该类型包含的属性和值。例如:
var dude = new { Name = "Bob", Age = 23 };编译器将会把上述语句(大致)转换为:
internal class AnonymousGeneratedTypeName { private string name; // 实际字段名无关紧要 private int age; // 实际字段名无关紧要 public AnonymousGeneratedTypeName(string name, int age) { this.name = name; this.age = age; } public string Name { get { return name; } } public int Age { get { return age; } } // Equals 和 GetHashCode 方法被重写。 // ToString 方法也被重写。 } var dude = new AnonymousGeneratedTypeName("Bob", 23);匿名类型只能通过 var 关键字来引用,因为它并没有一个名字。
匿名类型的属性名称可以从一个本身为标识符(或者以标识符结尾)的表达式推断得到,例如:
int Age = 23; var dude = new { Name = "Bob", Age, Age.ToString().Length };上述代码等价于:
var dude = new { Name = "Bob", Age = Age, Length = Age.ToString().Length };
在同一个程序集内声明的两个匿名类型实例,如果它们的元素名称和类型是相同的,那么它们在内部就是相同的类型:
var a1 = new { X = 2, Y = 4 }; var a2 = new { X = 2, Y = 4 }; Console.WriteLine(a1.GetType() == a2.GetType()); // True
此外,匿名类型还会重写 Equals 方法来执行结构化相等比较(即数据值的比较):
Console.WriteLine(a1.Equals(a2)); // True而相等运算符却执行引用比较:
Console.WriteLine(a1 == a2); // False
以下代码创建了一个匿名类型的数组:
var dudes = new[] { new { Name = "Bob", Age = 30 }, new { Name = "Tom", Age = 40 } };
匿名类型的对象无法通过方法有效地返回,因为将函数返回类型指定为 var 是非法的:
var Foo() => new { Name = "Bob", Age = 30 }; // Not legal!因此我们只得用 object 或者 dynamic 作为返回值,而每一个调用 Foo 方法的点都需要动态绑定,这种方式会丧失静态类型的安全性(以及 Visual Studio 的 IntelliSense):
dynamic Foo() => new { Name = "Bob", Age = 30 }; // No static type safety.
匿名类型是不可更改的,因此匿名类型的实例在创建之后无法进行改动。但是,在 C# 10 中,可以使用 with 关键字创建一个可变更的副本(非破坏性更改)。
var a1 = new { A = 1, B = 2, C = 3, D = 4, E = 5 }; var a2 = a1 with { E = 10 }; Console.WriteLine(a2); // { A = 1, B = 2, C = 3, D = 4, E = 10 }