为什么 C# 中的完整 属性 可以仅用 getter 覆盖,但仍然可以设置?
Why can a full property in C# be overridden with only a getter but it can still be set?
我遇到了一个让我吃惊的行为。给定以下两个 classes:
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 也让人感到困惑,因为虽然它允许赋值,但它也表明被覆盖的 属性 是只读的:
此外,仅当我使用基数 class' 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..ctor
IL_0005: ldc.i4.1
IL_0006: callvirt Parent.set_Property
IL_000B: ret
Parent.get_Property:
IL_0000: ldarg.0
IL_0001: ldfld Parent.<Property>k__BackingField
IL_0006: ret
Parent.set_Property:
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld Parent.<Property>k__BackingField
IL_0007: ret
Parent..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: ret
Child.get_Property:
IL_0000: ldarg.0
IL_0001: call Parent.get_Property
IL_0006: ret
Child..ctor:
IL_0000: ldarg.0
IL_0001: call Parent..ctor
IL_0006: ret
这是我的版本:
Main:
IL_0000: newobj Child..ctor
IL_0005: ldc.i4.1
IL_0006: callvirt Parent.SetProperty
IL_000B: ret
Parent.GetProperty:
IL_0000: ldarg.0
IL_0001: ldfld Parent._property
IL_0006: ret
Parent.SetProperty:
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld Parent._property
IL_0007: ret
Parent..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: ret
Child.GetProperty:
IL_0000: ldarg.0
IL_0001: call Parent.GetProperty
IL_0006: ret
Child..ctor:
IL_0000: ldarg.0
IL_0001: call Parent..ctor
IL_0006: ret
请注意,这与 public override bool Property { get; }
不同,shorthand 指示编译器为同名的后备 属性 生成单个 getter 覆盖,没有提及先前存在的 setter。但是,对实际规范有经验的人肯定能够提供更多相关信息。
我遇到了一个让我吃惊的行为。给定以下两个 classes:
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 也让人感到困惑,因为虽然它允许赋值,但它也表明被覆盖的 属性 是只读的:
此外,仅当我使用基数 class' 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..ctor
IL_0005: ldc.i4.1
IL_0006: callvirt Parent.set_Property
IL_000B: ret
Parent.get_Property:
IL_0000: ldarg.0
IL_0001: ldfld Parent.<Property>k__BackingField
IL_0006: ret
Parent.set_Property:
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld Parent.<Property>k__BackingField
IL_0007: ret
Parent..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: ret
Child.get_Property:
IL_0000: ldarg.0
IL_0001: call Parent.get_Property
IL_0006: ret
Child..ctor:
IL_0000: ldarg.0
IL_0001: call Parent..ctor
IL_0006: ret
这是我的版本:
Main:
IL_0000: newobj Child..ctor
IL_0005: ldc.i4.1
IL_0006: callvirt Parent.SetProperty
IL_000B: ret
Parent.GetProperty:
IL_0000: ldarg.0
IL_0001: ldfld Parent._property
IL_0006: ret
Parent.SetProperty:
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld Parent._property
IL_0007: ret
Parent..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: ret
Child.GetProperty:
IL_0000: ldarg.0
IL_0001: call Parent.GetProperty
IL_0006: ret
Child..ctor:
IL_0000: ldarg.0
IL_0001: call Parent..ctor
IL_0006: ret
请注意,这与 public override bool Property { get; }
不同,shorthand 指示编译器为同名的后备 属性 生成单个 getter 覆盖,没有提及先前存在的 setter。但是,对实际规范有经验的人肯定能够提供更多相关信息。