代码之家  ›  专栏  ›  技术社区  ›  rory.ap

为什么C#中的完整属性只能用getter重写,但仍然可以设置?

  •  8
  • rory.ap  · 技术社区  · 6 年前

    我遇到了一个令我惊讶的行为。考虑到以下两类:

    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也让人感到困惑,因为虽然它允许赋值,但它也指示重写的属性是只读的:

    enter image description here

    此外,只有在使用基类“getter:

    enter image description here

    这是怎么回事?

    1 回复  |  直到 6 年前
        1
  •  8
  •   Scott    6 年前

    我来试试看。

    看起来这可能只是Intellisense的一个bug,它无法找到auto属性的基本实现。代码是有效的,而且很有意义——下面是另一种表达示例的方法。

    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; } ,是指示编译器为同名的backing属性生成单个getter重写的简写,没有提及先前存在的setter。然而,有实际规范经验的人肯定能够提供更多关于这方面的信息。