C# · 12月 22, 2021

为什么C#中的完整属性只能被一个getter覆盖,但它仍然可以被设置?

我遇到了令我惊讶的行为.给出以下两个类: class Parent{ public virtual bool Property { get; set; }}class Child : Parent{ public override bool Property { get => base.Property; }}

我可以写这样的代码:

Child child = new Child();child.Property = true; // this is allowed

IDE也让它变得混乱,因为虽然它允许赋值,但它也表明被覆盖的属性是只读的:

此外,只有在我使用基类’getter时才允许此覆盖:

这里发生了什么?

解决方法 我会对此嗤之以鼻.

看起来这可能只是Intellisense的一个错误,它无法找到自动属性的基本实现.代码是有效的,也是有道理的 – 这是表达你的例子的另一种方式.

Child child = new Child();child.SetProperty(true);class Parent{ private bool _property; public virtual bool Getproperty() => _property; public virtual void SetProperty(bool value) => _property = value;}class Child : Parent{ public override bool Getproperty() => base.Getproperty();}

有了这种表示,现在很明显为什么重写GetProperty很好.这是您的代码的相关IL:

Main:IL_0000: newobj Child..ctorIL_0005: ldc.i4.1IL_0006: callvirt Parent.set_PropertyIL_000B: retParent.get_Property:IL_0000: ldarg.0IL_0001: ldfld Parent.<Property>k__backingFieldIL_0006: retParent.set_Property:IL_0000: ldarg.0IL_0001: ldarg.1IL_0002: stfld Parent.<Property>k__backingFieldIL_0007: retParent..ctor:IL_0000: ldarg.0IL_0001: call System.Object..ctorIL_0006: retChild.get_Property:IL_0000: ldarg.0IL_0001: call Parent.get_PropertyIL_0006: retChild..ctor:IL_0000: ldarg.0IL_0001: call Parent..ctorIL_0006: ret

这是我的版本:

Main:IL_0000: newobj Child..ctorIL_0005: ldc.i4.1IL_0006: callvirt Parent.SetPropertyIL_000B: retParent.GetProperty:IL_0000: ldarg.0IL_0001: ldfld Parent._propertyIL_0006: retParent.SetProperty:IL_0000: ldarg.0IL_0001: ldarg.1IL_0002: stfld Parent._propertyIL_0007: retParent..ctor:IL_0000: ldarg.0IL_0001: call System.Object..ctorIL_0006: retChild.GetProperty:IL_0000: ldarg.0IL_0001: call Parent.GetPropertyIL_0006: retChild..ctor:IL_0000: ldarg.0IL_0001: call Parent..ctorIL_0006: ret

请注意,这与公共覆盖bool Property {get; },是指示编译器为同名的后备属性生成单个getter覆盖的简写,没有提到预先存在的setter.然而,有实际规格经验的人肯定能够提供更多相关信息.