2013-08-12 5 views
46

с этогоПереопределение автоматического свойства

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

Интересный вопрос, и я не знаю ответа, но разве можно получить ответ через отражение или дизассемблер? – PVitt

+0

Не просто распределение, но сама вещь не должна существовать (поскольку 'get' также игнорирует ее). –

+2

@GrantThomas Поле базы данных все еще должно существовать в базовом классе, потому что вы можете получить к нему доступ таким образом: '((Base) childInstance) .MyInt' – MarcinJuraszek

ответ

52

Короткий ответ: Да, 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; } 
    } 
} 

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 

Is использует anotherInt поле, как вы могли бы ожидать.

Единственные способы доступа к '<MyInt>k__BackingField' (косвенно, через Base.MyInt собственности) являются:

  • base.MyInt внутри Child класса
+0

Есть ли разница между сборками Debug и Release? –

+1

@SimonWhitehead Это от выпуска. Я не думаю, что Debug здесь отличается. – MarcinJuraszek

+4

@SimonWhitehead Вы подразумеваете, что режим выпуска мог бы оптимизировать это? Я бы не подумал, так как есть еще много других углов, которые нужно было бы использовать в фоновом режиме. –

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

имя фактического поля подложки недокументированная деталь реализации, так что я бы не использовать его в любом производственный код. (Я получил его, используя IL-код LINQPad)

+0

Вы упомянули выше, что доступ к архиву не может быть доступен через (Base) childInstance) .MyInt. Можете ли вы проверить/подтвердить, что через отражение тоже, насколько многие другие утверждают, что это возможно. – PVitt

+0

@PVitt Это по определению полиморфизм. Если у меня есть «Список », и я вызываю метод «Говорить» на всех из них, собака должна лаять, кошка должна мяукать и т. Д., Независимо от того, на что они ссылаются через ссылку базового класса.Приведение дочернего экземпляра в качестве базы просто изменяет тип ссылки, оно ничего не делает для реального типа объекта. – SWeko

+0

Ну, это теория. Но поскольку большинство других заявляют, что на практике поле МОЖЕТ быть доступным, я хотел бы знать, что верно. У меня нет разборки, поэтому я не могу проверить себя. – PVitt

6

Это не просто эквивалент его фактической реализации. Компилятор перезаписывает ваши автоматические свойства на этапе прекомпиляции. Хотя имя поля будет называться чем-то другим.

В результате поведение будет идентично тому, как вы создадите свойство вручную.

Да, скрытое поле будет существовать, однако оно не будет назначено, потому что ваше переопределение не вызывает базовую реализацию.

если вы изменили переопределение

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

Тогда будет происходить выделение

2

MyInt поле будет там, и это нужно! Компилятор не может выполнить оптимизацию на основе информации о подклассе. Рассмотрим, например, что производный класс может не присутствовать в упакованной запущенной программе

обновлен, поскольку я неправильно понял часть вопроса. Спасибо @PVitt за указание.

+0

Это поле не должно использоваться другими методами в базовом классе, так как его имя не определено. Так что ваша вторая причина - не причина. – PVitt

Смежные вопросы