C # Propriétés automatiques – Pourquoi dois-je écrire “get; ensemble;”?

Si get et set sont tous deux obligatoires dans les propriétés automatiques C #, pourquoi devrais-je prendre la peine de spécifier “get; set;” du tout?

ERREUR: une propriété ou un indexeur ne peut pas être transmis en tant que paramètre out ou ref

Si vous n’avez pas spécifié {get; set;} {get; set;} alors le compilateur ne saura pas s’il s’agit d’un champ ou d’une propriété. Ceci est important car tant qu’ils “semblent” identiques, le compilateur les traite différemment. Par exemple, l’appel de “InitAnInt” sur la propriété génère une erreur.

 class Test { public int n; public int i { get; set; } public void InitAnInt(out int p) { p = 100; } public Test() { InitAnInt(out n); // This is OK InitAnInt(out i); // ERROR: A property or indexer may not be passed // as an out or ref parameter } } 

Vous ne devez pas créer de champs publics / variables sur les classes, vous ne savez jamais quand vous voudrez le modifier pour avoir des accesseurs get & set, et vous ne savez pas quel code vous allez briser, surtout si vous avez les clients qui programment contre votre API.

De plus, vous pouvez avoir différents modificateurs d’access pour get & set, par exemple {get; private set;} rend le public et le set privé à la classe déclarante.

Parce que vous pourriez vouloir une propriété en lecture seule:

 public int Foo { get; private set; } 

Ou propriété en écriture seule:

 public int Foo { private get; set; } 

Parce que vous avez besoin d’un moyen de le distinguer des champs simples.

Il est également utile d’avoir différents modificateurs d’access, par exemple

 public int MyProperty { get; private set; } 

Je pensais juste partager mes découvertes sur ce sujet.

Coder une propriété comme celle-ci est un appel de raccourci .net 3.0 « propriété implémentée automatiquement ».

 public int MyProperty { get; set; } 

Cela vous évite de taper. Le long chemin pour déclarer une propriété est comme ceci:

 private int myProperty; public int MyProperty { get { return myProperty; } set { myProperty = value; } } 

Lorsque vous utilisez la “propriété implémentée automatiquement”, le compilateur génère le code pour câbler le get et le définir sur “k_BackingField”. Vous trouverez ci-dessous le code démonté à l’aide de Reflector.

 public int MyProperty { [ComstackrGenerated] get { return this.k__BackingField; } [ComstackrGenerated] set { this.k__BackingField = value; } } 

code C # désassemblé de IL

Câbler également une méthode pour le setter et le getter.

 [ComstackrGenerated] public void set_MyProperty(int value) { this.k__BackingField = value; } [ComstackrGenerated] public int get_MyProperty() { return this.k__BackingField; } 

code C # désassemblé de IL

Lorsque vous déclarez une propriété implémentée en lecture seule, en définissant le paramètre setter sur private:

  public int MyProperty { get; private set; } 

Tout le compilateur ne marque pas le ” set ” comme privé. La méthode setter et getter disent la même chose.

 public int MyProperty { [ComstackrGenerated] get { return this.k__BackingField; } private [ComstackrGenerated] set { this.k__BackingField = value; } } 

code C # désassemblé de IL

Donc, je ne suis pas sûr pourquoi le cadre nécessite à la fois le get; Et mettre; sur une propriété implémentée automatiquement. Ils n’auraient tout simplement pas pu écrire la méthode set et setter si elle n’était pas fournie. Mais il y a peut-être un problème au niveau du compilateur qui rend cela difficile, je ne sais pas.

Si vous regardez le long moyen de déclarer une propriété en lecture seule:

 public int myProperty = 0; public int MyProperty { get { return myProperty; } } 

Et puis regardez le code démonté. Le setter n’est pas du tout présent.

 public int Test2 { get { return this._test; } } public int get_Test2() { return this._test; } 

code C # désassemblé de IL

Le compilateur doit savoir si vous voulez générer un getter et / ou un setter, ou peut-être déclarer un champ.

Si la propriété n’avait pas d’accesseurs, comment le compilateur le séparerait-il d’un champ? Et qu’est-ce qui le séparerait d’un champ?

Eh bien, évidemment, vous avez besoin d’un moyen de faire la distinction entre les champs et les propriétés. Mais les mots clés requirejs sont-ils vraiment nécessaires? Par exemple, il est clair que ces deux déclarations sont différentes:

 public int Foo; public int Bar { } 

Cela pourrait fonctionner. C’est-à-dire que c’est une syntaxe qu’un compilateur pourrait concevoir.

Mais alors vous arrivez à une situation où un bloc vide a une signification sémantique. Cela semble précaire.

Puisque personne ne l’a mentionné, vous pouvez rendre la propriété auto virtuelle et la remplacer:

 public virtual int Property { get; set; } 

S’il n’y avait pas de get / set, comment serait-il remplacé? Notez que vous êtes autorisé à remplacer le getter et non le setter :

 public override int Property { get { return int.MinValue; } } 

De plus, étant donné que depuis C # 6.0 (dans Visual Studio 2015, au moment de la réponse disponible dans la version Ultimate Preview), vous pouviez implémenter une véritable propriété en lecture seule:

 public ssortingng Name { get; } public ssortingng Name { get; } = "This won't change even internally"; 

… par opposition à une solution de contournement actuellement imparfaite avec un paire de setter public / privé:

 public ssortingng Name { get; private set; } public Constructor() { Name="As initialised"; } public void Method() { Name="This might be changed internally. By mistake. Or not."; } 

Exemple ci-dessus ci-dessous (compilé et exécutable en ligne ici ).

 using System; public class Propertier { public ssortingng ReadOnlyPlease { get; private set; } public Propertier() { ReadOnlyPlease="As initialised"; } public void Method() { ReadOnlyPlease="This might be changed internally"; } public override ssortingng ToSsortingng() { return Ssortingng.Format("[{0}]",ReadOnlyPlease); } } public class Program { static void Main() { Propertier p=new Propertier(); Console.WriteLine(p); // p.ReadOnlyPlease="Changing externally!"; // Console.WriteLine(p); // error CS0272: The property or indexer `Propertier.ReadOnlyPlease' cannot be used in this context because the set accessor is inaccessible // That's good and intended. // But... p.Method(); Console.WriteLine(p); } } 

Autres nouvelles savoureuses sur C # 6.0 disponibles en avant-première officielle ici .