Hvorfor er det nødvendig å ringe: dette () på en struct å bruke automatiske egenskaper i C #?

stemmer
52

Hvis jeg definere en struct i C # ved hjelp av automatiske egenskaper som dette:

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

Når jeg prøver å bygge filen, får jeg en kompileringsfeil ordtak The 'this' object cannot be used before all of its fields are assigned to. Dette kan løses ved å endre konstruktøren å lage en lenket anrop til standardkonstruktøren som dette:

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

Mitt spørsmål er, hvorfor dette arbeidet, og hva som skjer? Jeg har en gjetning, og jeg prøvde å bevise det ved å se på IL, men jeg bare tuller meg selv om jeg tror jeg kan bryte ned IL. Men min gjetning er, auto egenskaper virker ved at kompilatoren generere felt for eiendommene bak kulissene. Disse feltene kan ikke nås gjennom koden, alle innstillingen og får må gjøres gjennom eiendommene. Når du oppretter en struct, en standard konstruktør kan ikke eksplisitt definert. Så bak kulissene, må kompilatoren genererer en standard konstruktør som setter verdiene i feltene som utbygger ikke kan se.

Enhver og alle IL veivisere er velkommen til å bevise eller motbevise teorien min.

Publisert på 07/11/2008 klokken 14:06
kilden bruker
På andre språk...                            


2 svar

stemmer
52

Merk: fra C # 6, dette er ikke nødvendig - men du bør bruke read-only automatisk-implementert eiendommer med C # 6 uansett ...

this()sørger for at feltene er definitivt tildelt så langt som kompilatoren er opptatt - det setter alle felt til standardverdiene. Du må ha et fullt konstruert struct før du kan begynne å bruke noen egenskaper.

Det er irriterende, men det er slik det er. Er du sikker på at du virkelig vil at dette skal være en struct skjønt? Og hvorfor bruke en beskyttet setter på en struct (som ikke kan utledes fra)?

Svarte 07/11/2008 kl. 14:10
kilden bruker

stemmer
0

En egenskap er noe mer enn en innkapsling av en Getmetode og / eller en Setmetode. CLR har metadata som indikerer at spesielle metoder bør anses som å være en egenskaper, noe som betyr at kompilatorer bør tillate noen konstruksjoner som det ikke ville tillate med metoder. For eksempel, hvis Xen lese-skrive eiendom Foo, en kompilator vil oversette Foo.X += 5til Foo.SET_X_METHOD(Foo.GET_X_METHOD() + 5)(selv om metodene er et annet navn, og er generelt ikke tilgjengelig med navn).

Selv om en autoproperty implementerer et par av get / herdingsfremgangsmåter som aksesserer en privat felt på en slik måte som for å oppføre seg mer eller mindre som et felt, fra det synspunkt av en hvilken som helst kode utenfor egenskapen, er en autoproperty et par av få / set metoder akkurat som annen bolig. Følgelig en uttalelse som Foo.X = 5;er oversatt som Foo.SET_X_METHOD(5). Siden C # kompilatoren bare ser det som en metode samtale, og siden metoder inkluderer ikke eventuelle metadata for å indikere hvilke felt de lese eller skrive, vil kompilatoren forby metodekallet hvis ikke det vet alle felt av Foohar blitt skrevet.

Personlig ville mitt råd være å unngå bruk av autoproperties med strukturtypene. Autoproperties fornuftig med klasser, siden det er mulig for klasseegenskaper for å støtte funksjoner som oppdateringsvarsler. Selv om tidlige versjoner av en klasse ikke støtter oppdateringsvarsler, vil ha disse versjonene bruke en autoproperty snarere enn et felt betyr at fremtidige versjoner kan legge update-varsling funksjoner uten å kreve forbrukerne av klassen som skal omarbeides. Strukturer, men kan ikke meningsfull støtte de fleste av de typer funksjoner som man kanskje ønsker å legge til felt-lignende egenskaper.

Videre ytelse forskjeller mellom felt og egenskaper er mye større med større konstruksjoner enn det er med klassetyper. Ja, mye av anbefalingen om å unngå store strukturer er en konsekvens av denne forskjellen. Store konstruksjoner kan faktisk være svært effektiv, hvis man unngår å kopiere dem unødvendig. Selv om man hadde en enorm struktur HexDecet<HexDecet<HexDecet<Integer>>>, der HexDecet<T>finnes utsatte områder F0.. F15av type T, en uttalelse som Foo = MyThing.F3.F6.F9;ville bare kreve å lese en heltall fra MyThingog lagre det til Foo, selv om MyThingville ved enorme av struct standarder (4096 heltall opptar 16K). I tillegg kan man oppdatere dette elementet veldig lett, f.eks MyThing.F3.F6.F9 += 26;. Derimot, hvis F0.. F15var auto-egenskaper, oppstilling Foo = MyThing.F3.F6.F9ville kreve kopiering 1K av data fra MyThing.F3til en midlertidig (kaller det temp1, deretter 64 byte med data fra temp1.F6til temp2) før endelig får å lese 4 byte data fra temp2.F9. Æsj. Verre, prøver å legge 26 til verdien i MyThing.F3.F6.F9ville kreve noe sånt var t1 = MyThing.F3; var t2 = t1.F6; t2.F9 += 26; t1.F6 = f2; MyThing.F3 = t1;.

Mange av de langvarige klager på "foranderlig strukturtypene" er egentlig klager på strukturtypene med lese- / skriveegenskaper. Bare erstatte eiendommer med felt og problemene forsvinner.

PS: Det er tider det kan være nyttig å ha en struktur med egenskaper tilgang til en klasse objektet den holder en referanse. For eksempel ville det være fint å ha en versjon av en ArraySegment<T>klasse som tillot en å si Var foo[] = new int[100]; Var MyArrSeg = New ArraySegment<int>(foo, 25, 25); MyArrSeg[6] += 9;, og har den siste setningen legger ni til element (25 + 6) på foo. I eldre versjoner av C # en kunne gjøre det. Dessverre, den hyppige bruken av autoproperties i ramme hvor felt ville vært mer hensiktsmessig førte til omfattende klager på kompilatoren tillate eiendoms settere å bli kalt uselessly på read-only strukturer; derfor kaller noen eiendom setter på en skrivebeskyttet strukturen er nå forbudt, hvorvidt eiendommen setter faktisk vil endre noen felt av struct. Hvis folk bare hadde avstått fra å gjøre structs foranderlig via eiendoms settere (lage felt direkte tilgjengelig når mutability var riktig) kompilatorer ville aldri hatt til å gjennomføre den begrensningen.

Svarte 01/10/2012 kl. 15:46
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more