首页 > 编程笔记 > C#笔记 阅读:2

C#匿名类型的用法(附带实例)

C# 中的匿名类型是一个由编译器临时创建的类,它用于存储一组值。

如果需要创建一个匿名类型,则可以使用 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 }

相关文章