Perché l’assegnazione di null in ternary operator fallisce: nessuna conversione implicita tra null e int?

Questo fallisce con a There is no implicit conversion between 'null' and 'int'

 long? myVar = Int64.Parse( myOtherVar) == 0 ? null : Int64.Parse( myOtherVar); 

Tuttavia, questo ha esito positivo:

 if( Int64.Parse( myOtherVar) == 0) myVar = null; else myVar = Int64.Parse( myOtherVar); 

C’è un modo per far funzionare l’operatore ternario?

Il compilatore ignora il lato sinistro quando capisce il tipo del lato destro. Quindi quando cerca di dedurre il tipo di

 Int64.Parse(myOtherVar) == 0 ? null : Int64.Parse(myOtherVar) 

lo fa senza prestare attenzione al fatto che il lato sinistro è long? . Per determinare il tipo di lato destro, lo nota

 Int64.Parse(myOtherVar) 

è un long e ora prova a vedere se null è o può essere convertito implicitamente in un long . Dal momento che non può, ottieni il messaggio di errore che vedi.

Dal § 7.1 delle specifiche C #:

Un’espressione condizionale del modulo b ? x : y b ? x : y ….

Il secondo e il terzo operando, x e y , dell’operatore ?: Controllano il tipo di espressione condizionale.

(1) Se x ha tipo X e y ha tipo Y allora

un. Se una conversione implicita (§6.1) esiste da X a Y , ma non da Y a X , allora Y è il tipo di espressione condizionale.

b. Se esiste una conversione implicita (§6.1) da Y a X , ma non da X a Y , X è il tipo di espressione condizionale.

c. Altrimenti, non è ansible determinare alcun tipo di espressione e si verifica un errore in fase di compilazione.

(2) Se solo uno tra x e y ha un tipo, ed entrambi y , di sono convertibili in modo implicito per quel tipo, allora questo è il tipo di espressione condizionale.

(3) Altrimenti, non è ansible determinare alcun tipo di espressione e si verifica un errore in fase di compilazione.

Nota che siamo in situazione (2) dove x è null e non ha un tipo y è Int64.Parse(myOtherVar) e ha tipo long . Si noti che x non è implicitamente convertibile nel tipo di y . Quindi entrambi (1) e (2) falliscono sopra e risultiamo in (3) che risulta nell’errore di compilazione che ha ispirato la tua domanda. Si noti la conclusione implicita da quanto sopra che il lato sinistro non ha un ruolo nel determinare il tipo di lato destro.

Per rimediare a questa sostituzione

 Int64.Parse(myOtherVar) 

con

 (long?)Int64.Parse(myOtherVar) 

Ora, la ragione per cui

 myVar = null; 

va bene dove myVar è dichiarato come long? è perché il compilatore sa che esiste una conversione implicita da null a long? .

Infine, Int64.Parse genererà se myOtherVar non può essere analizzato a long . Nota che stai anche eseguendo l’analisi due volte, il che non è necessario. Un modello migliore è

 long value; if(Int64.TryParse(myOtherVar, out value)) { myVar = value == 0 ? null : (long?)value; } else { // handle case where myOtherVar couldn't be parsed } 

L’utilizzo dell’operatore restituisce un Int64 , non un valore nullable , a causa dell’ultima parte dell’operatore ternario. Potrebbe funzionare se invece lo fai:

 long? myVar = Int64.Parse( myOtherVar) == 0 ? null : (long?)Int64.Parse( myOtherVar); 

In modo che tu stia tornando un long? invece, quindi il null non ha bisogno di essere convertito in Int64

Inoltre, stai convertendo il valore due volte nel tuo codice, inutilmente (una volta per testare e una volta per ottenere il valore). Il tuo codice potrebbe essere migliore in questo modo:

 long? tempVar = Int64.Parse(myOtherVar); long? myVar = tempVar==0? null : tempVar; 

Sono sicuro che intendevi dire:

  myVar = value == 0 ? null : (long?)value; 

invece di

  myVar = value == 0 ? null : value; 

Mi è piaciuto l’uso della variabile ‘out’. Grazie.

Questo funzionerà:

 long? myVar = (long?)myOtherVar == 0 ? null : (long?)myOtherVar; 

..per coloro a cui piacciono le risposte brevi.

Il compilatore tenta di valutare le espressioni da sinistra a destra

 long? myVar = Int64.Parse( myOtherVar) == 0 ? null : Int64.Parse( myOtherVar); 

int64.parse metodo int64.parse restituisce un valore long non un valore long int64.parse . quindi non c’è conversione tra null e Int64.Parse( myOtherVar); Quindi, prova questo

 long? myVar = Int64.Parse(myOtherVar) == 0 ? (long?) null : Int64.Parse(myOtherVar); 

O
long? myVar = Int64.Parse(myOtherVar) == 0 ? null : (long?) Int64.Parse(myOtherVar);