2015-09-10 8 views
14

Durante la lettura di un comment ad una risposta ho visto il seguente costrutto di dichiarare e inizializzare una variabile:Utilizzando una variabile come un argomento fuori al punto di dichiarazione

int variable = int.TryParse(stringValue, out variable) ? variable : 0; 

È questo permesso, corretta e ben definita in C# ? Cosa succede sotto il cofano? È il seguente cosa succede?

  1. Is variable inizializzato a zero?
  2. quindi passato a int.TryParse (che assegna un valore)?
  3. quindi a scelta (se int.TryParse restituisce true)?
  4. e quindi, ancora una volta assegnato/inizializzato?
+1

1. No (le variabili locali non sono assegnate per impostazione predefinita) –

+0

2. Sì, * out * significa che verrà assegnato il valore –

risposta

8

Questo è un trucco che sembra funzionare perché è semplicemente una riscrittura di un'istruzione if comune.Questo codice è equivalente alla presente:

int variable; 
if (int.TryParse(stringVariable, out variable)) 
    variable = variable; 
else 
    variable = 0; 

La sequenza è la seguente:

int.TryParse viene chiamato, variable non viene inizializzato prima di questo, ma non deve neanche. Un parametro out non richiede una variabile assegnata definita. Come parte dell'esecuzione del metodo, al valore variable verrà assegnato un valore e int.TryParse restituirà true o false.

Se il metodo restituisce true allora il risultato del espressione sarà variable e quindi abbiamo eseguirà fondamentalmente variable = variable.

Se il metodo restituisce false allora il risultato della espressione sarà invece 0, e variable verrà ora dato il valore 0 indipendentemente da quello che è stato somministrato come parte di int.TryParse. In questo caso, tuttavia, ciò non cambierà la variabile poiché int.TryParse ha già assegnato il valore predefinito a variable quando restituisce false, che corrisponde anche a 0.

Questo è fondamentalmente un modo per ottenere tutto su un'unica riga.

Personalmente avrei scritto questo codice come questo:

int variable; 
int.TryParse(stringValue, out variable); 
+0

Personalmente avrei scritto il codice come nella tua ultima riga, aggiungendo una riga in più nella misura di // Se TryParse fallisce inizializza la variabile = 0. Sono sicuro che altrimenti mi confonderebbe in futuro :) – CompuChip

6

int variable dichiara variable, e out variable necessariamente inizializza esso. Entrambe queste cose devono accadere prima che lo variable venga utilizzato ovunque e, a causa della dichiarazione out, ciò è vero.

Come indicate da Lasse V. Carlsen, da TryParse's documentation, TryParse sarà di default assegnare il valore del 0 se la conversione fallisce:

Quando termina, questo metodo [return] contiene 32 bit numero intero con segno equivalente del numero contenuto in s, se la conversione è riuscita, o zero se la conversione non è riuscita. (emph mio.)

Se si espande la funzione ternario fuori, vedreste:

int variable; 
if (int.TryParse(stringValue, out variable)) 
    variable = variable; 
else 
    variable = 0; 

che è, di per sé, un espressione giuridica. I due percorsi sono:

  • TryParse assegna il valore di variable e restituisce true, portando ad una cessione di variable per sé
  • TryParse inizializza variable a 0 e restituisce falso, portando alla assegnazione di variable come zero la condizione ternaria

Questo non è un codice particolarmente chiaro, tuttavia, e non consiglierei di farlo.

+2

In realtà, se 'TryParse' restituisce' false', deve ancora impostare 'variable', e in questo caso è [documentato] (https://msdn.microsoft.com/en-us/library/f02979c7 (v = vs.110) .aspx) da inizializzare a '0': quando questo metodo ritorna, contiene il valore intero con segno a 32 bit equivalente al numero contenuto in s, se la conversione è riuscita, ** o zero se la conversione non è riuscita. ** * (il mio accento) * –

+0

@ LasseV.Karlsen Grazie! L'ho modificato nella risposta. – Zyerah

+0

@ LasseV.Karlsen: Sebbene 'int.TryParse' sia documentato come sempre scrivendo la variabile passata (impostandola a zero in caso di errore), non c'è in generale alcuna garanzia che una funzione scritta in un'altra lingua scriverà a' out' parametri prima di tornare. Personalmente, penso che il pattern "try" avrebbe dovuto essere "T TryComputeSomething (params, out SuccessOrfailure success;)", con il caso di errore restituire "default (T)". [Avrei 'SuccessOrFailure' essere una classe con singleton definiti per il successo o il fallimento, ma supportando la possibilità di aggiungere più informazioni pure]. – supercat

1

Non ho aperto Visual Studio per provare questo, ma sì, questo è permesso.

Tutto dipende dalla variabile "stringValue". Se questo è analizzabile in un numero intero, int.TryParse restituirà true e [variabile] avrà un valore intero. In caso contrario, il valore

è impostato su 0.

Questo rende il codice leggibile? Apparentemente no.

10

Sì hai ragione per l'esecuzione. È anche possibile guardare in MSIL generato qui

C# Codice

string stringValue = "5"; 
int variable = int.TryParse(stringValue, out variable) ? variable : 0; 

MSIL generato

1. IL_0000: nop  
2. IL_0001: ldstr  "5" // load string 
3. IL_0006: stloc.0 
4. IL_0007: ldloc.0 
5. IL_0008: ldloca.s variable 
6. IL_000a: call  bool [mscorlib]System.Int32::TryParse(string, int32&) 
7. IL_000f: brtrue.s IL_0014 
8. IL_0011: ldc.i4.0 
9. IL_0012: br.s  IL_0015 
10. IL_0014: ldloc.1 
11. IL_0015: stloc.1 
12. IL_0016: ret 

che chiarisce quello che fa dietro le quinte.

L'istruzione 5 assegna la variabile allo stack. L'istruzione 6 sta chiamando il metodo. L'istruzione 7,8,9 sta effettivamente utilizzando l'espressione bool.

Problemi correlati