Pourquoi est-il nécessaire d’appeler: this () sur une structure pour utiliser les propriétés automatiques dans c #?

Si je définis une structure en C # en utilisant des propriétés automatiques comme ceci:

public struct Address { public Address(ssortingng line1, ssortingng line2, ssortingng city, ssortingng state, ssortingng zip) { Line1 = line1; Line2 = line2; City = city; State = state; Zip = zip; } public ssortingng Line1 { get; protected set; } public ssortingng Line2 { get; protected set; } public ssortingng City { get; protected set; } public ssortingng State { get; protected set; } public ssortingng Zip { get; protected set; } } 

Lorsque je tente de générer le fichier, je reçois une erreur de compilation en disant que The 'this' object cannot be used before all of its fields are assigned to . Cela peut être résolu en changeant le constructeur pour qu’il fasse un appel chaîné au constructeur par défaut comme ceci:

 public Address(ssortingng line1, ssortingng line2, ssortingng city, ssortingng state, ssortingng zip): this() { Line1 = line1; Line2 = line2; City = city; State = state; Zip = zip; } 

Ma question est la suivante: pourquoi cela fonctionne-t-il et que se passe-t-il? Je suppose, et j’ai essayé de le prouver en regardant IL, mais je me moque seulement si je pense que je peux briser IL. Mais à mon avis, les propriétés automatiques fonctionnent en faisant en sorte que le compilateur génère des champs pour vos propriétés en arrière-plan. Ces champs ne sont pas accessibles via le code, tous les paramétrages doivent être effectués via les propriétés. Lors de la création d’une structure, un constructeur par défaut ne peut pas être défini explicitement. En arrière-plan, le compilateur doit générer un constructeur par défaut qui définit les valeurs des champs que le développeur ne peut pas voir.

Tous les assistants IL sont les bienvenus pour prouver ou réfuter ma théorie.

Note: à partir de C # 6, ce n’est pas obligatoire – mais vous devriez quand même utiliser des propriétés implémentées en lecture seule avec C # 6 …

this() s’assure que les champs sont définitivement affectés en ce qui concerne le compilateur – cela définit tous les champs à leurs valeurs par défaut. Vous devez avoir une structure entièrement construite avant de pouvoir accéder aux propriétés.

C’est agaçant, mais c’est comme ça. Êtes-vous sûr que vous voulez vraiment que ce soit une structure si? Et pourquoi utiliser un setter protégé sur une structure (qui ne peut pas être dérivé)?

Une propriété n’est rien d’autre qu’une encapsulation d’une méthode Get et / ou d’une méthode Set . Le CLR a des métadonnées qui indiquent que des méthodes particulières devraient être considérées comme des propriétés, ce qui signifie que les compilateurs devraient autoriser certaines constructions qu’elles ne permettraient pas avec des méthodes. Par exemple, si X est une propriété en lecture-écriture de Foo , un compilateur traduira Foo.X += 5 en Foo.SET_X_METHOD(Foo.GET_X_METHOD() + 5) (bien que les méthodes soient nommées différemment et ne soient généralement pas accessibles) de nom).

Bien qu’une autoproperty implémente une paire de méthodes get / set qui accèdent à un champ privé de manière à se comporter plus ou moins comme un champ, du sharepoint vue de tout code extérieur à la propriété, une autoproperty est une paire de get / définir des méthodes comme toute autre propriété. Par conséquent, une déclaration comme Foo.X = 5; est traduit par Foo.SET_X_METHOD(5) . Comme le compilateur C # ne voit que cela comme un appel de méthode, et que les méthodes n’incluent aucune métadonnée pour indiquer quels champs elles lisent ou écrivent, le compilateur interdira l’appel de méthode à moins qu’il connaisse tous les champs de Foo .

Personnellement, mon conseil serait d’éviter l’utilisation de propriétés automatiques avec des types de structure. Les propriétés automatiques ont du sens avec les classes, car il est possible que les propriétés de classe prennent en charge des fonctionnalités telles que les notifications de mise à jour. Même si les premières versions d’une classe ne prennent pas en charge les notifications de mise à jour, le fait que ces versions utilisent un autoproperty plutôt qu’un champ signifie que les futures versions peuvent append des fonctionnalités de notification de mise à jour sans avoir à retravailler les utilisateurs. Les structures, cependant, ne peuvent pas prendre en charge de manière significative la plupart des types d’entités que l’on peut souhaiter append aux propriétés de type champ.

En outre, les différences de performances entre les champs et les propriétés sont beaucoup plus grandes avec les grandes structures qu’avec les types de classe. En effet, une grande partie de la recommandation d’éviter les grandes structures est une conséquence de cette différence. Les grandes structures peuvent effectivement être très efficaces, si l’on évite de les copier inutilement. Même si on avait une structure énorme HexDecet>> , où HexDecet contenait des champs exposés F0 .. F15 de type T , une instruction comme Foo = MyThing.F3.F6.F9; exigerait simplement de lire un entier de MyThing et de le stocker dans Foo , même si MyThing serait énorme par rapport aux normes structurées (4096 entiers occupant 16K). De plus, on pourrait mettre à jour cet élément très facilement, par exemple MyThing.F3.F6.F9 += 26; . En revanche, si F0 .. F15 était auto-propriétés, l’instruction Foo = MyThing.F3.F6.F9 nécessiterait de copier 1K de données de MyThing.F3 vers un temporaire (appelez-le temp1 , puis 64 octets de temp1.F6 à temp2 ) avant de pouvoir enfin lire 4 octets de données à partir de temp2.F9 . Ick. Pire, essayer d’append 26 à la valeur dans MyThing.F3.F6.F9 nécessiterait quelque chose comme var t1 = MyThing.F3; var t2 = t1.F6; t2.F9 += 26; t1.F6 = f2; MyThing.F3 = t1; var t1 = MyThing.F3; var t2 = t1.F6; t2.F9 += 26; t1.F6 = f2; MyThing.F3 = t1; .

Bon nombre des plaintes de longue date concernant les “types de structure mutables” sont vraiment des plaintes concernant les types de structure avec des propriétés de lecture / écriture. Remplacez simplement les propriétés par des champs et les problèmes disparaissent.

PS: Il est parfois utile d’avoir une structure dont les propriétés accèdent à un object de classe auquel elle est associée. Par exemple, il serait intéressant d’avoir une version d’une ArraySegment permettant de dire Var foo[] = new int[100]; Var MyArrSeg = New ArraySegment(foo, 25, 25); MyArrSeg[6] += 9; Var foo[] = new int[100]; Var MyArrSeg = New ArraySegment(foo, 25, 25); MyArrSeg[6] += 9; et que la dernière déclaration ajoute neuf à l’élément (25 + 6) de foo . Dans les anciennes versions de C #, on pouvait le faire. Malheureusement, l’utilisation fréquente d’auto-propriétés dans le cadre, où les champs auraient été plus appropriés, a suscité de nombreuses plaintes concernant le compilateur, ce qui a permis d’invoquer les concepteurs de propriétés sur des structures en lecture seule. par conséquent, l’appel de tout setter de propriétés sur une structure en lecture seule est désormais interdit, que le setter de propriétés modifie ou non des champs de la structure. Si les gens s’étaient simplement abstenus de rendre les structures modifiables via les propriétés (rendant les champs directement accessibles lorsque la mutabilité était appropriée), les compilateurs n’auraient jamais eu à implémenter cette ressortingction.