覆盖一个自动属性

从此

public int MyInt{ get; set;} 

相当于

 private int _myInt; public int MyInt{ get{return _myInt;} set{_myInt = value;} } 

当你使虚拟自动属性

 public virtual int MyInt{ get; set;} 

然后在子类中重写此属性

 public override int MyInt{ get{return someVar;} set{someVar = value;} } 

这个孩子class现在有一个不受欢迎和隐藏的分配_myInt?

简答 :是的, Child分配所有Base类字段,所以它仍然有分配的后台字段。 但是,除了通过Base.MyInt属性之外,您不能以任何其他方式访问它。

长答案

快速拆卸结果。

Base类和Child类的实现:

 public class Base { public virtual int MyInt { get; set; } } public class Child : Base { private int anotherInt; public override int MyInt { get { return anotherInt; } set { anotherInt = value; } } } 

在这里输入图像说明

如您所见,后台字段存在于Base类中。 但是,它是私人的,所以你不能从Child类访问它:

 .field private int32 '<MyInt>k__BackingField' 

而您的Child.MyInt属性不使用该字段。 酒店IL是:

 .method public hidebysig specialname virtual instance int32 get_MyInt () cil managed { // Method begins at RVA 0x2109 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld int32 ConsoleApplication2.Child::anotherInt IL_0006: ret } // end of method Child::get_MyInt .method public hidebysig specialname virtual instance void set_MyInt ( int32 'value' ) cil managed { // Method begins at RVA 0x2111 // Code size 8 (0x8) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: stfld int32 ConsoleApplication2.Child::anotherInt IL_0007: ret } // end of method Child::set_MyInt 

正如你所期望的那样使用anotherInt字段。

访问'<MyInt>k__BackingField' (间接通过Base.MyInt属性)的唯一方法是:

  • Child类中的base.MyInt

这不仅仅是等同于实际的实现。 编译器在预编译阶段重写自动属性。 虽然字段名称将被命名别的东西。

因此,行为将与您手动创build属性相同。

是隐藏字段将存在,但不会被分配给,因为您的重写不会调用基本实现。

如果你改变覆盖

 public override int MyInt { get { return someVar; } set { someVar = value; base.MyInt = value } } 

然后分配会发生

是的,就好像它没有被定义为自动属性一样。

基类中需要分配,因为它仍然需要存在并且有用。 基类不知道派生类的存在,派生类可以在其定义中使用后台字段

如果你有一个基类和派生类定义如下:

 public class Base { public virtual string Name {get; set;} } public class Derived : Base { private string _name; public override string Name { get { return _name; } set { //access the base property we are overriding base.Name = value + " from derived"; _name = value; } } } 

您可以使用reflection来查看基类的支持字段确实存在,并按预期行为:

 Type tbase = typeof(Base); FieldInfo fi = tbase.GetField("<Name>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance); Base b = new Base {Name = "Test"}; string baseValue = fi.GetValue(b).ToString(); Console.WriteLine(baseValue); //gives "Test"; Derived d = new Derived {Name = "Test" }; string derivedValue = fi.GetValue(d).ToString(); Console.WriteLine(derivedValue); //gives "Test from derived"; 

实际支持字段的名称是一个未公开的实现细节,所以我不会在任何生产代码中使用它。 (我通过使用LINQPad的IL视图得到它)

MyInt字段将在那里,它需要! 编译器不能根据子类信息进行优化。 例如,考虑派生类可能不会出现在打包的运行程序中

因为我误解了部分问题而更新。 感谢@PVitt指出。