Remplacement d’une propriété automatique

depuis cela

public int MyInt{ get; set;} 

est équivalent à

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

quand vous faites la propriété automatique virtuelle

 public virtual int MyInt{ get; set;} 

puis remplacez cette propriété dans une classe enfant

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

cette classe enfant a-t-elle maintenant une allocation non désirée et cachée de _myInt?

Réponse courte : Oui, l’ Child alloue tous les champs de la classe de Base , ainsi le champ de sauvegarde est toujours alloué. Cependant, vous ne pouvez pas y accéder autrement que via la propriété Base.MyInt .

Réponse longue :

Déassembly rapide

Base classes Base et 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; } } } 

entrer la description de l'image ici

Comme vous pouvez le voir, le champ de sauvegarde existe dans la classe de Base . Cependant, il est privé, vous ne pouvez donc pas y accéder depuis Child classe Child :

 .field private int32 'k__BackingField' 

Et votre propriété Child.MyInt n’utilise pas ce champ. La propriété IL est:

 .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 utilise un anotherInt champ, comme on pouvait s’y attendre.

Les seuls moyens d’accéder à 'k__BackingField' (indirectement, via la propriété Base.MyInt ) sont les suivants:

  • base.MyInt partir de Child classe Child

Ce n’est pas simplement l’équivalent de sa mise en œuvre réelle. Le compilateur réécrit vos propriétés automatiques dans sa phase de précompilation. Bien que le nom du champ soit nommé autre chose.

Par conséquent, le comportement sera identique à la création manuelle de la propriété.

Oui, le champ masqué existera, mais il ne sera pas affecté car votre remplacement n’appelle pas l’implémentation de base.

si vous avez changé le remplacement à

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

Ensuite, l’allocation se produirait

Oui, comme si ce n’était pas défini comme une propriété automatique.

L’allocation est nécessaire dans la classe de base, car elle doit toujours exister et être utile. La classe de base ne connaît pas l’existence de la classe dérivée et la classe dérivée peut utiliser le champ de sauvegarde dans sa définition

Si vous avez une base et une classe dérivée définies comme:

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

Vous pouvez utiliser la reflection pour voir que le champ de sauvegarde de la classe de base existe bel et bien et se comporte comme prévu:

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

Le nom du champ de sauvegarde réel est un détail d’implémentation non documenté, donc je ne l’utiliserais dans aucun code de production. (Je l’ai eu en utilisant la vue IL de LINQPad)

Le champ MyInt sera là et il le faut! Le compilateur ne peut pas faire d’optimisation en fonction des informations de la sous-classe. Considérons par exemple que la classe dérivée peut ne pas être présente dans le programme en cours d’exécution

mis à jour car j’avais mal lu une partie de la question. Merci @PVitt pour avoir souligné.