覆盖自动属性

时间:2013-08-12 08:09:01

标签: c#

因为这个

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;} }

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

4 个答案:

答案 0 :(得分:54)

简短回答 :是的,Child分配了所有Base类字段,因此它仍然分配了支持字段。但是,除了通过Base.MyInt属性之外,您无法以任何其他方式访问它。

长答案

快速反汇编结果。

BaseChild类实现:

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; }
    }
}

enter image description here

正如您所看到的,支持字段存在于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属性)的唯一方法是:

  • base.MyInt来自Child

答案 1 :(得分:6)

它不仅仅与实际实现相当。编译器会在预编译阶段重写自动属性。虽然字段名称将被命名为其他名称。

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

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

如果您将覆盖更改为

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

然后分配将会发生

答案 2 :(得分:3)

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

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

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

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;
    }
  }
}

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

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 View获得的)

答案 3 :(得分:2)

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

已更新因为我误读了部分问题。谢谢@PVitt指出。