47 votes

Ignorer 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 redéfinissez 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 invitée et cachée de _myInt?

55voto

MarcinJuraszek Points 66084

Réponse courte: Oui, l' Child alloue tous Base champs de la classe, donc il a encore le champ de stockage alloué. Cependant, vous ne pouvez pas y accéder autrement que par Base.MyInt de la propriété.

Réponse Longue:

Rapide démontage des résultats.

Base et Child des classes de mise en œuvre:

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

Comme vous pouvez le voir, le champ de stockage existe au sein de l' Base classe. Cependant, il est privé, donc vous ne pouvez pas y accéder à partir d' Child classe:

.field private int32 '<MyInt>k__BackingField'

Et votre Child.MyInt de la propriété de ne pas utiliser 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

Est utilise anotherInt champ, que l'on pourrait attendre.

Les seuls moyens d'accéder à l' '<MyInt>k__BackingField' (indirectement, par le biais Base.MyInt de la propriété) sont:

  • base.MyInt de dans les Child classe

6voto

Bob Vale Points 11355

Ce n'est pas seulement l'équivalent à peu près la mise en œuvre effective. Le compilateur écrit de votre automatique des propriétés de son précompiler scène. Quoique le nom du champ sera nommé quelque chose d'autre.

En conséquence, le comportement sera identique à la création de la propriété manuellement.

Oui cachés champ existe, cependant il ne sera pas affecté, parce que votre substituer à ne pas faire appel à la base de la mise en œuvre.

si vous avez changé le remplacement

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

Ensuite, la répartition se ferait

3voto

SWeko Points 17524

Oui, tout comme si elle n'était pas définie comme une automatique bien.

La répartition est nécessaire dans la classe de base, car il a encore besoin d'exister et d'être utile. La classe de base n'a pas connaissance de l'existence de la dérivée de la classe, et la classe dérivée peut utiliser le champ de stockage dans sa définition

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

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

Vous pouvez utiliser la réflexion pour voir que le champ de stockage de la base de classe existe bel et bien, et se comporte comme prévu:

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

Le nom du champ de stockage est un sans-papiers, la mise en œuvre du détail, donc je ne voudrais pas l'utiliser dans la production de code. (Je l'ai eu en utilisant LINQPad IL Vue)

2voto

coffeebreaks Points 1482

Le champ MyInt sera là et il le faut! Le compilateur ne peut pas utiliser l'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 interprété une partie de la question. Merci à @PVitt pour cette remarque.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X