2009-04-15 11 views

risposta

14

I campi vengono automaticamente inizializzati sullo zero logico del tipo; questo è implicito. Le variabili devono obbedire al "compito definito", quindi deve essere assegnato prima di poter essere letto.

ECMA 334v4

§17.4.4 inizializzazione campo

Il valore iniziale di un campo, sia esso un campo statico o un campo istanza , è il valore predefinito (§12.2) di il tipo di campo. Non è possibile osservare il valore di un campo prima dello si è verificata questa inizializzazione predefinita e un campo non è mai "non inizializzato".

e

§12. Variabili

... Una variabile deve essere assegnata definitivamente (§12.3) prima che sia possibile ottenere il valore . ...

+0

questo è solo ripetere la domanda. Ma perché? –

+0

@YairHalberstadt che dipende da "perché?" uno significa la regola o la ragione dietro la regola. Ho risposto al primo, che probabilmente risponde alla domanda; per il secondo: perché quando hai considerato il concatenamento del costruttore, i metodi virtuali chiamati durante la costruzione e il fatto che i costruttori di base a livello IL possano essere chiamati in qualsiasi punto della catena di chiamate, diventa quasi impossibile dire qualcosa ragionevole sull'inizializzazione del campo; allo stesso modo, i campi possono essere sovrapposti rendendo ancora più importante azzerare lo spazio, quindi non è tecnicamente necessario alcun init - contrasto ... –

+0

@YairHalberstadt variabili locali, che hanno un controllo di assegnazione molto semplice, dove uninitialized di solito significa un errore, e dove può saltare l'azzeramento (anche se il runtime corrente non lo fa mai, IIRC). –

4

In realtà non dovrebbe. Il tuo errore dovrebbe essere sulla seconda riga, non il primo, e dovrebbe essere perché l'hai USATO prima di inizializzarlo.

Il compilatore ti sta aiutando.

Quindi non inizializzarli come un'abitudine, invece lascia che il compilatore ti aiuti!

La cosa bella di questo è che si verificherà il percorso per te. Se hai un'istruzione switch con 3 casi in cui ognuno imposta il valore ma ti dimentichi di impostarlo nel tuo "predefinito" ma lo usi in seguito ti avviserà che hai perso un percorso.

Se si inizializzano le variabili su = 0, si toglie tale vantaggio.

+0

Ho usato anche test1 prima di inizializzarlo, ma era ok –

+0

Sì, lo stesso controllo non è utile con le variabili di classe - non c'è modo di tracciare il percorso di quelle a meno che non le rendiate definitive, quindi dovrebbe assicurare che siano compilato nel costruttore (una buona idea, ove possibile) –

+0

Anche se il controllo del percorso non è troppo elaborato. Es .: diciamo che hai qualcosa del genere: 'bool a, b = true; se (b) a = true; bool c = a; '. La terza affermazione ** genererà l'errore, anche se noi, umani, vediamo chiaramente che a questo punto sarà ** inizializzato **. Il compilatore non osserva le condizioni interne, anche quando sono così semplici e sempre vere. (E quindi vale anche per i casi più complicati). – Sushi271

2

Come indica Marc, questo è quello che dice la specifica. La ragione per cui questa è una buona cosa è che ci sono alcuni validi motivi per lasciare un membro non inizializzato piuttosto che una variabile locale, la cui durata è limitata dal metodo in cui si trova. Principalmente lo si vorrebbe solo per ragioni di prestazioni, se il la variabile è costosa da inizializzare e deve essere inizializzata solo in specifici scenari di utilizzo. Per parte mia, eviterei i membri non inizializzati fino a che la mia schiena non fosse veramente contro il muro, però!

Per le variabili locali, è anche molto più facile rilevare se tutti i percorsi di codice possono portare all'inizializzazione, mentre non ci sono buone euristiche per determinare se tutti i percorsi di codice nell'intero programma garantiscono l'inizializzazione prima dell'uso. Una risposta completamente corretta è impossible in both cases, come dovrebbero sapere tutti gli studenti CS.

12

Estensione della risposta di Mark, l'inizializzazione della variabile locale è anche correlata al processo di verifica .
La CLI richiede che in qualsiasi codice verificabile (ovvero moduli che non hanno chiesto esplicitamente di saltare la procedura di verifica utilizzando la proprietà SkipVerfication dell'attributo SecurityPermission), tutte le variabili locali devono essere inizializzate prima del loro utilizzo. In caso contrario, verrà generato un valore pari a VerficationException.

Più interessante è che il compilatore aggiunge automaticamente il flag .locals init su ogni metodo che utilizza variabili locali. Questo flag fa in modo che il compilatore JIT generi codice che inizializza tutte le variabili locali ai loro valori predefiniti. Significa che, anche se li hai già inizializzati nel tuo codice, il JIT si conformerà al flag .locals init e genererà il codice di inizializzazione corretto. Questa "inizializzazione duplicata" non influisce sulle prestazioni poiché nelle configurazioni che consentono ottimizzazioni, il compilatore JIT rileverà la duplicazione e la tratterà efficacemente come "codice morto" (la routine di inizializzazione generata automaticamente non verrà visualizzata nelle istruzioni assembler generate).

Secondo Microsoft (anche, sostenuto da Eric Lippert in risposta a una domanda sul suo blog), nella maggior parte dei casi, quando i programmatori non inizializzano la loro variabile locale, non lo fanno perché si inoltrano sul l'ambiente sottostante per inizializzare la loro variabile sono valori predefiniti, ma solo perché "dimenticati", causando così dei bug logici a volte illusivi.
Quindi, al fine di ridurre la probabilità che i bug di questa natura appaiano nel codice C#, il compilatore insiste ancora che si inizializzeranno le variabili locali. Anche se aggiungerà il flag .locals init al codice IL generato.

Una spiegazione più esauriente su questo argomento si possono trovare qui: Behind The .locals init Flag

Problemi correlati