在记录中定义属性两次
c#
c#-9.0
在 C# 9 中,可以在记录的主构造函数和主体中定义同名属性:
record Cat(int PawCount)
{
public int PawCount { get; init; }
}
这段代码编译没有错误。
初始化此类记录的实例时,提供给构造函数的值将被完全忽略:
Console.WriteLine(new Cat(4));
Console.WriteLine(new Cat(4) { PawCount = 1 });
印刷
Cat { PawCount = 0 }
Cat { PawCount = 1 }
这种行为是正确的还是错误?如果它是正确的,它在哪些情况下有用?
我希望编译器要么拒绝此代码,并显示“类型Cat已经包含PawCount'的定义”之类的错误,要么将构造函数中的属性和主体中的属性视为相同,从构造函数执行其初始化。后一种变体可用于为属性提供自定义 getter 和/或初始值设定项,而无需在其主体中重写位置记录的所有属性。
实际行为对我来说毫无意义。
回答
正确的做法是:
record Cat(int PawCount)
{
public int PawCount { get; init; } = PawCount;
}
这很有用,因为它允许您进行例如验证
record Cat(int PawCount)
{
private int _pawCount;
public int PawCount {
get => _pawCount;
init => _pawCount = value < 0 ? throw new ArgumentException() : value;
} = PawCount;
}
这个规范在这里:https : //github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/records.md#members-of-a-record-type
除非在记录正文中声明具有“匹配”签名的成员或继承具有“匹配”签名的可访问的具体非虚拟成员,否则成员将被合成。如果两个成员具有相同的签名或在继承场景中将被视为“隐藏”,则两个成员被视为匹配。
因此,由于与参数同名的属性已经存在,编译器不会合成PawCount属性,因此除非您自己明确使用它,否则只会默默地忽略该参数。
-
https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/records.md#members-of-a-record-type
"Members are synthesized unless a member with a "matching" signature is declared in the record body or an accessible concrete non-virtual member with a "matching" signature is inherited. Two members are considered matching if they have the same signature or would be considered "hiding" in an inheritance scenario."