.Netto 2+:perché if( 1 == null ) non lancia più un'eccezione del compilatore?
-
09-06-2019 - |
Domanda
sto usando int
come esempio, ma questo si applica a qualsiasi tipo di valore in .Net
In .Net 1 quanto segue genererebbe un'eccezione del compilatore:
int i = SomeFunctionThatReturnsInt();
if( i == null ) //compiler exception here
Ora (in .Net 2 o 3.5) quell'eccezione è scomparsa.
So perché è così:
int? j = null; //nullable int
if( i == j ) //this shouldn't throw an exception
Il problema è che perché int?
è nullable e int
ora ha un cast implicito a int?
.La sintassi sopra è magia del compilatore.Stiamo davvero facendo:
Nullable<int> j = null; //nullable int
//compiler is smart enough to do this
if( (Nullable<int>) i == j)
//and not this
if( i == (int) j)
Quindi ora, quando lo faremo i == null
noi abbiamo:
if( (Nullable<int>) i == null )
Dato che C# sta comunque eseguendo la logica del compilatore per calcolarlo, perché non può essere abbastanza intelligente da non farlo quando si ha a che fare con valori assoluti come null
?
Soluzione
Non penso che sia un problema del compilatore di per sé;un valore intero non è mai nullo, ma l'idea di equipararli non è invalida;è una funzione valida che restituisce sempre false.E il compilatore lo sa;il codice
bool oneIsNull = 1 == null;
compila, ma fornisce un avviso al compilatore: The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type '<null>'
.
Quindi, se vuoi ripristinare l'errore del compilatore, vai alle proprietà del progetto e attiva "tratta gli avvisi come errori" per questo errore e inizierai a vederli di nuovo come problemi che compromettono la compilazione.
Altri suggerimenti
Strano ...compilandolo con VS2008, destinato a .NET 3.5:
static int F()
{
return 42;
}
static void Main(string[] args)
{
int i = F();
if (i == null)
{
}
}
Ricevo un avviso del compilatore
warning CS0472: The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type 'int?'
E genera il seguente IL...che presumibilmente la JIT ottimizzerà
L_0001: call int32 ConsoleApplication1.Program::F()
L_0006: stloc.0
L_0007: ldc.i4.0
L_0008: ldc.i4.0
L_0009: ceq
L_000b: stloc.1
L_000c: br.s L_000e
Puoi postare uno snippet di codice?
Il compilatore genera comunque un avviso quando si confronta il tipo non nullable con null, che è proprio come dovrebbe essere.Potrebbe essere che il tuo livello di avviso sia troppo basso o che questo sia stato modificato nelle versioni recenti (l'ho fatto solo in .net 3.5).
Il framework 2.0 ha introdotto il tipo di valore nullable.Anche se la costante letterale "1" non può mai essere nulla, il tipo sottostante (int) può ora essere convertito in un tipo int Nullable.La mia ipotesi è che il compilatore non possa più presumere che i tipi int non siano nullable, anche quando si tratta di una costante letterale.Ricevo un avviso durante la compilazione 2.0:
Attenzione 1 Il risultato dell'espressione è sempre 'false' poiché un valore di tipo 'int' non è mai uguale a 'null' di tipo 'int?'
L'avviso è nuovo (3.5 credo): l'errore è lo stesso che se lo avessi fatto 1 == 2
, che è abbastanza intelligente da individuare come mai vero.
Ho il sospetto che con le ottimizzazioni 3.5 complete l'intera affermazione verrà semplicemente eliminata, poiché è piuttosto intelligente con valutazioni mai vere.
Anche se potrei volerlo 1==2
compilare (per disattivare un blocco funzione mentre provo qualcos'altro, ad esempio) non voglio 1==null
A.
Dovrebbe trattarsi di un errore in fase di compilazione, perché i tipi sono incompatibili (i tipi di valore non possono mai essere nulli).È piuttosto triste che non lo sia.