因为这个
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分配吗?
答案 0 :(得分:54)
简短回答 :是的,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
属性)的唯一方法是:
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指出。