Perché è necessario chiamare: this () su uno struct per usare le proprietà automatiche in c #?

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

Domanda

Se definisco una struttura in C # usando proprietà automatiche come questa:

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

Quando provo a creare il file, viene visualizzato un errore di compilazione che dice The 'this' object cannot be used before all of its fields are assigned to. Questo può essere risolto cambiando il costruttore per effettuare una chiamata concatenata al costruttore predefinito come questo:

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

La mia domanda è: perché funziona e cosa sta succedendo? Ho un'ipotesi e ho provato a dimostrarlo guardando IL, ma mi sto prendendo in giro solo se penso di poter abbattere IL. Ma la mia ipotesi è che le proprietà automatiche funzionano facendo in modo che il compilatore generi campi per le tue proprietà dietro le quinte. Non è possibile accedere a questi campi tramite il codice, tutte le impostazioni e il recupero devono essere effettuati tramite le proprietà. Durante la creazione di una struttura, non è possibile definire esplicitamente un costruttore predefinito. Quindi, dietro le quinte, il compilatore deve generare un costruttore predefinito che imposta i valori dei campi che lo sviluppatore non può vedere.

Tutti i maghi IL sono invitati a provare o smentire la mia teoria.

È stato utile?

Soluzione

Nota: a partire da C # 6, questo non è necessario, ma dovresti comunque utilizzare le proprietà implementate automaticamente di sola lettura con C # 6 ...

this() si assicura che i campi siano definitivamente assegnati per quanto riguarda il compilatore - imposta tutti i campi sui loro valori predefiniti. Devi avere una struttura completamente costruita prima di poter iniziare ad accedere a qualsiasi proprietà

È fastidioso, ma è così. Sei sicuro di voler davvero che questa sia una struttura? E perché usare un setter protetto su una struttura (da cui non è possibile derivare)?

Altri suggerimenti

Una proprietà non è altro che un'incapsulamento di un metodo Get e / o Set. Il CLR ha metadati che indicano che particolari metodi dovrebbero essere considerati come proprietà, il che significa che i compilatori dovrebbero consentire alcuni costrutti che non consentirebbe con i metodi. Ad esempio, se X è una proprietà di lettura / scrittura di Foo, un compilatore tradurrà Foo.X += 5 in Foo.SET_X_METHOD(Foo.GET_X_METHOD() + 5) (sebbene i metodi abbiano un nome diverso e generalmente non siano accessibili per nome).

Sebbene l'autoproperty implementa una coppia di metodi get / set che accedono a un campo privato in modo tale da comportarsi più o meno come un campo, dal punto di vista di qualsiasi codice esterno alla proprietà, l'autoproperty è una coppia dei metodi get / set proprio come qualsiasi altra proprietà. Di conseguenza, un'istruzione come Foo.X = 5; viene tradotta in Foo.SET_X_METHOD(5). Poiché il compilatore C # lo vede solo come una chiamata di metodo e poiché i metodi non includono alcun metadata per indicare quali campi leggono o scrivono, il compilatore proibirà la chiamata di metodo a meno che non sappia che tutti i campi di HexDecet<HexDecet<HexDecet<Integer>>> sono stati scritti.

Personalmente, il mio consiglio sarebbe di evitare l'uso di autoproperties con tipi di strutture. Autoproperties ha senso con le classi, poiché è possibile che le proprietà delle classi supportino funzionalità come le notifiche di aggiornamento. Anche se le prime versioni di una classe non supportano le notifiche di aggiornamento, se tali versioni utilizzano l'autoproperty anziché un campo, le versioni future possono aggiungere funzionalità di notifica degli aggiornamenti senza richiedere la rielaborazione dei consumatori della classe. Le strutture, tuttavia, non possono supportare significativamente la maggior parte dei tipi di funzionalità che si potrebbero desiderare di aggiungere a proprietà simili a campi.

Inoltre, le differenze di prestazioni tra campi e proprietà sono molto maggiori con le strutture di grandi dimensioni rispetto ai tipi di classe. In effetti, gran parte della raccomandazione di evitare grandi strutture è una conseguenza di questa differenza. Le grandi strutture possono effettivamente essere molto efficienti, se si evita di copiarle inutilmente. Anche se uno avesse una struttura enorme HexDecet<T>, dove F0 conteneva campi esposti F15 .. T di tipo Foo = MyThing.F3.F6.F9;, un'istruzione come MyThing richiederebbe semplicemente la lettura di un intero da MyThing.F3.F6.F9 += 26; e la memorizzazione a Foo = MyThing.F3.F6.F9, anche se MyThing.F3 sarebbe enormemente secondo gli standard di struct (4096 numeri interi che occupano 16K). Inoltre, si potrebbe aggiornare quell'elemento molto facilmente, ad es. temp1. Al contrario, se temp1.F6 .. temp2 fossero proprietà automatiche, l'istruzione temp2.F9 richiederebbe la copia di 1K di dati da MyThing.F3.F6.F9 a un temporaneo (chiamalo var t1 = MyThing.F3; var t2 = t1.F6; t2.F9 += 26; t1.F6 = f2; MyThing.F3 = t1;, quindi 64 byte di dati da <= > a ArraySegment<T>) prima di iniziare a leggere 4 byte di dati da Var foo[] = new int[100]; Var MyArrSeg = New ArraySegment<int>(foo, 25, 25); MyArrSeg[6] += 9;. Ick. Peggio ancora, provare ad aggiungere 26 al valore in foo richiederebbe qualcosa come <=>.

Molte delle lamentele di vecchia data relative a " tipi di strutture mutabili " sono davvero lamentele sui tipi di struttura con proprietà di lettura / scrittura. Sostituisci semplicemente le proprietà con i campi e i problemi scompaiono.

PS: a volte può essere utile avere una struttura le cui proprietà accedono a un oggetto di classe a cui contiene un riferimento. Ad esempio, sarebbe bello avere una versione di una classe <=> che permettesse di dire <=> e che l'ultima istruzione aggiungesse nove all'elemento (25 + 6) di <=>. Nelle versioni precedenti di C # si poteva farlo. Sfortunatamente, l'uso frequente di autoproperties nel Framework in cui i campi sarebbero stati più appropriati ha portato a diffuse lamentele sul compilatore che consente ai setter di proprietà di essere chiamati inutilmente su strutture di sola lettura; di conseguenza, è ora vietato chiamare qualsiasi setter di proprietà su una struttura di sola lettura, indipendentemente dal fatto che il setter di proprietà modifichi effettivamente qualsiasi campo della struttura. Se le persone si fossero semplicemente astenute dal rendere mutevoli le strutture tramite i setter di proprietà (rendendo i campi direttamente accessibili quando la mutabilità era appropriata) i compilatori non avrebbero mai dovuto applicare tale restrizione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top