Nullable types e l’operatore ternario: perché è `? 10: null` vietato?

Ho appena trovato un errore strano:

private bool GetBoolValue() { //Do some logic and return true or false } 

Quindi, in un altro metodo, qualcosa del genere:

 int? x = GetBoolValue() ? 10 : null; 

Semplice, se il metodo restituisce true, assegna 10 a Nullable int x. Altrimenti, assegna null al nullable int. Tuttavia, il compilatore si lamenta:

Errore 1 Imansible determinare il tipo di espressione condizionale poiché non esiste una conversione implicita tra int e .

Sto impazzendo?

Il compilatore prima tenta di valutare l’espressione della mano destra:

 GetBoolValue() ? 10 : null 

Il 10 è un letterale int (non int? ) E null è, beh, null . Non c’è conversione implicita tra questi due quindi il messaggio di errore.

Se si modifica l’espressione della mano destra in uno dei seguenti, viene compilata perché esiste una conversione implicita tra int? e null (# 1) e tra int e int? (# 2, # 3).

 GetBoolValue() ? (int?)10 : null // #1 GetBoolValue() ? 10 : (int?)null // #2 GetBoolValue() ? 10 : default(int?) // #3 

Prova questo:

 int? x = GetBoolValue() ? 10 : (int?)null; 

Fondamentalmente ciò che sta accadendo è che l’operatore condizionale non è in grado di determinare il “tipo di ritorno” dell’espressione. Dal momento che il compilatore decide implicitamente che 10 è un int , allora decide che il tipo di ritorno di questa espressione deve essere anche un int . Poiché un int non può essere null (il terzo operando dell’operatore condizionale) si lamenta.

Lanciare il null a Nullable diciamo esplicitamente al compilatore che il tipo restituito di questa espressione deve essere un Nullable . Avresti potuto facilmente convertire il 10 in int? e ha avuto lo stesso effetto.

Prova questo:

int? result = condition ? 10 : default(int?);

Per inciso, l’implementazione di Microsoft del compilatore C # ottiene effettivamente l’analisi del tipo dell’operatore condizionale errata in un modo molto sottile e interessante (per me). Il mio articolo su di esso è di tipo I problemi di inferenza, prima parte .

Prova uno di questi:

 int? x = GetBoolValue() ? (int?)10 : null; int? x = GetBoolValue() ? 10 : (int?)null; 

Il problema è che l’operatore ternario sta inferendo il tipo basato sulla prima assegnazione di parametro … 10 in questo caso, che è un int, non un int nullable.

Potresti avere più fortuna con:

 int? x = GetBoolValue() (int?)10 : null; 
 int? x = GetBoolValue() ? 10 : (int?)null; 

La ragione per cui vedi questo è perché dietro le quinte stai usando Nullable e devi dire a C # che il tuo “null” è un’istanza null di Nullable.

Basta aggiungere un cast esplicito.

 int? x = GetBoolValue() ? 10 : (int?)null; 

È l’operatore ternario a essere confuso: il secondo argomento è un numero intero, quindi anche il terzo argomento è un numero intero, e null non si adatta.

È perché il compilatore determina il tipo di operatore condizionale dal suo secondo e terzo operando, non da ciò a cui si assegna il risultato. Non esiste una trasmissione diretta tra un numero intero e un riferimento null che il compilatore può utilizzare per determinare il tipo.