53 votes

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

Si je définis une struct en C# à l'aide automatique des propriétés de ce type:

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

    public string Line1 { get; protected set; }
    public string Line2 { get; protected set; }
    public string City { get; protected set; }
    public string State { get; protected set; }
    public string Zip { get; protected set; }
}

Lorsque je tente de générer le fichier, j'obtiens une erreur de compilation en disant: "Le" il "de l'objet ne peut pas être utilisé avant que l'ensemble de ses champs sont affectés". Cela peut être résolu en changeant le constructeur pour faire un enchaînés appel au constructeur par défaut comme ceci:

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

Ma question est, pourquoi cela fonctionne, et ce qui se passe? J'ai une supposition, et j'ai essayé de le prouver en le regardant IL, mais je ne suis moquez de moi-même si je pense que je peux briser IL. Mais ma conjecture est, auto propriétés travail en ayant le compilateur de générer des champs de vos propriétés derrière les coulisses. Ces champs ne sont pas accessibles à l'aide de code, tous les réglages et prise doit être fait par le biais des propriétés. Lors de la création d'une structure (struct), un constructeur par défaut ne peut pas être défini de façon explicite. Donc, derrière les coulisses, le compilateur doit être la génération d'un constructeur par défaut qui définit les valeurs des champs que le développeur ne peut pas voir.

Toutes et tous IL les assistants sont les bienvenus pour confirmer ou infirmer ma théorie.

52voto

Jon Skeet Points 692016

this() s'assure que les champs sont définitivement attribués au compilateur - il définit tous les champs sur leurs valeurs par défaut. Vous devez avoir une structure entièrement construite avant de pouvoir accéder à toutes les propriétés.

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

0voto

supercat Points 25534

Une propriété n'est rien de plus qu'une encapsulation d'un Get méthode et/ou un Set méthode. Le CLR a métadonnées qui indique que les méthodes particulières doivent être considérés comme étant une des propriétés, sens compilateurs devrait permettre à certaines constructions qui ne permettrait pas avec des méthodes. Par exemple, si X est une propriété en lecture-écriture de l' Foo, un compilateur va traduire Foo.X += 5 en Foo.SET_X_METHOD(Foo.GET_X_METHOD() + 5) (si les méthodes sont nommés différemment, et ne sont généralement pas accessibles par leur nom).

Bien qu'un autoproperty met en œuvre une paire de méthodes get/set dont l'accès à une zone privée de manière à se comporter plus ou moins comme un champ, du point de vue de n'importe quel code à l'extérieur de la propriété, un autoproperty est une paire de méthodes get/set, tout comme toute autre propriété. Par conséquent, une instruction comme celle - Foo.X = 5; est traduit Foo.SET_X_METHOD(5). Depuis le compilateur C# ne voit que comme un appel de méthode, et puisque les méthodes ne comprennent pas toutes les métadonnées pour indiquer que les champs de lecture ou d'écriture, le compilateur va interdire l'appel de la méthode, à moins qu'il connaît tous les domaines de l' Foo a été écrit.

Personnellement, mon conseil serait d'éviter l'utilisation de autoproperties avec les types de structure. Autoproperties faire du sens avec les classes, puisqu'il est possible pour des propriétés de la classe de fonctions de support comme les notifications de mise à jour. Même si les premières versions d'une classe ne supportent pas les notifications de mise à jour, d'avoir ces versions utilisent un autoproperty plutôt qu'un champ de dire que les futures versions pouvez ajouter de mise à jour-les fonctions de notification sans exiger les consommateurs de la classe à être retravaillé. Toutefois, les Structures ne peuvent pas de manière significative en charge la plupart des types de caractéristiques que l'on pourrait le souhaiter pour ajouter un champ des propriétés similaires.

En outre, les différences de performances entre les champs et les propriétés est beaucoup plus grande avec de grandes structures que c'est avec des 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 efficace, si l'on évite les copier inutilement. Même si l'on avait un énorme structure HexDecet<HexDecet<HexDecet<Integer>>>HexDecet<T> contenus exposés champs F0..F15 de type T, une instruction comme celle - Foo = MyThing.F3.F6.F9; serait tout simplement besoin de la lecture d'un entier compris entre MyThing et de le stocker dans Foo, même si MyThing serait énorme par struct normes (4096 entiers occupant 16K). En outre, on pourrait mettre à jour cet élément très facilement, par exemple, MyThing.F3.F6.F9 += 26;. En revanche, si F0..F15 ont été auto-propriétés, l'énoncé Foo = MyThing.F3.F6.F9 nécessiterait la copie de 1K de données à partir d' MyThing.F3 temporaire (appelons - temp1, 64 octets de données à partir d' temp1.F6 de temp2) avant de finalement se déplacer à la lecture de 4 octets de données à partir d' temp2.F9. Ick. Pire, en essayant d'ajouter 26 de la valeur en MyThing.F3.F6.F9 aurait besoin de quelque chose comme var t1 = MyThing.F3; var t2 = t1.F6; t2.F9 += 26; t1.F6 = f2; MyThing.F3 = t1;.

De nombreuses plaintes de longue date au sujet de "mutable types de structure" sont en réalité des plaintes au sujet de la structure avec des types de propriétés en lecture/écriture. Il suffit de remplacer les propriétés de champs et les problèmes disparaissent.

PS: Il y a des moments, il peut être utile de disposer d'une structure dont les propriétés accéder à une classe d'objets à laquelle elle détient une référence. Par exemple, il serait bien d'avoir une version de l' ArraySegment<T> de la classe qui lui permettait de dire Var foo[] = new int[100]; Var MyArrSeg = New ArraySegment<int>(foo, 25, 25); MyArrSeg[6] += 9;, et la dernière déclaration ajouter de neuf à l'élément (25+6) foo. Dans les anciennes versions de C# on pourrait le faire. Malheureusement, l'utilisation fréquente de autoproperties dans le Cadre où les champs aurait été plus approprié entraîné des plaintes concernant le compilateur permettant de propriété organismes de normalisation pour être appelé inutilement sur les structures; par conséquent, l'appel à tout le setter de la propriété en lecture seule structure est désormais interdite, que ce soit ou non la propriété setter serait effectivement de modifier tous les champs de la structure. Si les gens avaient tout simplement s'abstenir de faire des structures mutables via des accesseurs de propriété (prise de champs directement accessible lors de la mutabilité était approprié) les compilateurs n'auraient jamais eu à mettre en œuvre du fait de cette restriction.

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