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

StackOverflow https://stackoverflow.com/questions/272153

Question

Si je définis une structure en C # à l'aide de propriétés automatiques telles que:

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 j'essaie de créer le fichier, une erreur de compilation s'affiche en indiquant The 'this' object cannot be used before all of its fields are assigned to. Cela peut être résolu en changeant le constructeur pour faire un appel chaîné 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 la suivante: pourquoi cela fonctionne-t-il et que se passe-t-il? Je devine, et j'ai essayé de le prouver en regardant IL, mais je me moque de moi-même si je pense pouvoir briser l'IL. Mais je suppose que les propriétés automatiques fonctionnent en laissant le compilateur générer des champs pour vos propriétés en coulisse. L'accès à ces champs est impossible via le code. Tous les paramètres doivent être définis via les propriétés. Lors de la création d'une structure, un constructeur par défaut ne peut pas être explicitement défini. Donc, en coulisse, 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 invités à prouver ou à réfuter ma théorie.

Était-ce utile?

La solution

Remarque: à partir de C # 6, cela n'est pas obligatoire - mais vous devriez quand même utiliser des propriétés en lecture seule automatiquement implémentées avec C # 6 ...

this() s'assure que les champs sont définitivement assigné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 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)?

Autres conseils

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 contient des métadonnées qui indiquent que des méthodes particulières doivent être considérées comme des propriétés, ce qui signifie que les compilateurs doivent autoriser certaines constructions qu’il ne permettrait 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 par nom).

Bien qu'une propriété automatique 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 point de vue de tout code extérieur à la propriété, une propriété automatique est une paire des méthodes get / set comme n'importe quelle autre propriété. Par conséquent, une déclaration telle que Foo.X = 5; est traduite par Foo.SET_X_METHOD(5). Étant donné que le compilateur C # ne voit que cela comme un appel de méthode et que les méthodes n'incluent aucune métadonnée indiquant les champs lus ou écrits, le compilateur interdisera l'appel de méthode s'il ne sait pas que tous les champs de HexDecet<HexDecet<HexDecet<Integer>>> ont été écrits. / p>

Personnellement, mon conseil serait d'éviter l'utilisation de propriétés automatiques avec des types de structure. Les propriétés automatiques ont un 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 une propriété automatique plutôt qu'un champ signifie que les versions futures pourront ajouter des fonctionnalités de notification de mise à jour sans nécessiter de retravailler les utilisateurs de la classe. Cependant, les structures ne peuvent pas prendre en charge de manière significative la plupart des types de fonctionnalités que l’on pourrait souhaiter ajouter aux propriétés de type champ.

De plus, 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 en réalité être très efficaces, si l’on évite de les copier inutilement. Même si on avait une énorme structure HexDecet<T>, où F0 contenait des champs exposés F15 .. T de type Foo = MyThing.F3.F6.F9;, une instruction comme MyThing exigerait simplement la lecture d'un entier de MyThing.F3.F6.F9 += 26; et son stockage. Foo = MyThing.F3.F6.F9, même si MyThing.F3 le ferait énormément selon les normes de structure (4096 entiers occupant 16K). De plus, vous pouvez mettre à jour cet élément très facilement, par exemple temp1 En revanche, si temp1.F6 .. temp2 était une propriété automatique, l'instruction temp2.F9 nécessiterait de copier 1K de données de MyThing.F3.F6.F9 dans un temporaire (appelez-le var t1 = MyThing.F3; var t2 = t1.F6; t2.F9 += 26; t1.F6 = f2; MyThing.F3 = t1;, puis 64 octets de données de <= > à ArraySegment<T>) avant de pouvoir enfin lire 4 octets de données dans Var foo[] = new int[100]; Var MyArrSeg = New ArraySegment<int>(foo, 25, 25); MyArrSeg[6] += 9;. Ick. Pire, essayer d'ajouter 26 à la valeur dans foo nécessiterait quelque chose comme <=>.

La plupart des plaintes de longue date concernant & "les types de structures mutables &"; sont vraiment des plaintes sur les types de structure avec des propriétés de lecture / écriture. Il suffit de remplacer 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 objet de classe pour lequel elle contient une référence. Par exemple, il serait bien d’avoir une version d’une classe <=> qui permette de dire <=>, et d’ajouter la dernière instruction neuf à l’élément (25 + 6) de <=>. Dans les anciennes versions de C #, on pouvait le faire. Malheureusement, l’utilisation fréquente de propriétés automatiques dans le Framework, où des champs auraient été plus appropriés, a entraîné de nombreuses plaintes concernant le compilateur, permettant ainsi aux passeurs de propriété d’être appelés inutilement sur des structures en lecture seule; par conséquent, il est maintenant interdit d'appeler un créateur de propriété sur une structure en lecture seule, que le créateur de propriété modifie ou non les champs de la structure. Si les gens s'étaient simplement abstenus de rendre les structures mutables via des paramètres de propriété (rendre les champs directement accessibles lorsque la mutabilité était appropriée), les compilateurs n'auraient jamais eu à mettre en œuvre cette restriction.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top