覆盖一个自动属性
从此
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指出。