2008-09-15 7 views
5

ich int als Beispiel bin mit, aber das gilt für jeden Werttyp in .Net.Net 2+: Warum wird If (1 == null) keine Compiler-Ausnahme mehr werfen?

In .Net 1 der folgenden würde einen Compiler Ausnahme auslösen:

int i = SomeFunctionThatReturnsInt(); 

if(i == null) //compiler exception here 

Now (in .Net 2 oder 3.5) diese Ausnahme ist weg.

Ich weiß, warum das so ist:

int? j = null; //nullable int 

if(i == j) //this shouldn't throw an exception 

Das Problem ist, dass, weil int? NULL-Werte zulässt und int nun eine implizite Umwandlung zu int? hat. Die obige Syntax ist Compiler Magie. Wirklich wir tun:

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) 

So, jetzt, wenn wir i == null tun wir bekommen:

if((Nullable<int>) i == null) 

Da C# Compiler Logik tut dies berechnen sowieso, warum kann es nicht klug genug sein, um zu tun Sie es nicht, wenn Sie mit absoluten Werten wie null umgehen?

Antwort

3

Ich glaube nicht, dass dies ein Compiler-Problem ist per se; Ein ganzzahliger Wert ist niemals null, aber die Idee, sie gleichzusetzen, ist nicht ungültig. es ist eine gültige Funktion, die immer falsch zurückgibt. Und der Compiler weiß es; der Code

bool oneIsNull = 1 == null; 

kompiliert, sondern gibt eine Compiler-Warnung: The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type '<null>'.

Also, wenn Sie den Compiler-Fehler zurück wollen, gehen Sie zu den Projekteigenschaften und aktivieren Sie 'Warnungen als Fehler behandeln' für diesen Fehler, und Sie werden beginnen, sie als build-breaking Probleme wieder zu sehen.

1

Der Compiler generiert immer noch eine Warnung, wenn Sie einen nicht nullbaren Typ mit null vergleichen, was genau so ist, wie es sein sollte. Möglicherweise ist Ihre Warnstufe zu niedrig oder dies wurde in den letzten Versionen geändert (ich habe das nur in .net 3.5 getan).

3

Odd ... dies mit VS2008 kompilieren, Targeting .NET 3.5:

static int F() 
    { 
     return 42; 
    } 

    static void Main(string[] args) 
    { 
     int i = F(); 

     if (i == null) 
     { 
     } 
    } 

ich einen Compiler

warning CS0472: The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type 'int?' 

Und es generiert die folgende IL ..., die vermutlich den JIT-Warnung

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 

Können Sie ein Code-Snippet posten?

+0

Der Compiler erkennt korrekt, dass es nie wahr ist, als ob Sie 1 == 2 getan hätten. Es ist schlau genug zu wissen, dass int implizit in int umgewandelt werden kann? und das int? kann mit null verglichen werden. Ich vermute, der Optimierer ist schlau genug, um den ganzen Block auszublenden. – Keith

0

Die Warnung ist neu (3,5 ich denke) - der Fehler ist der gleiche wie wenn ich 1 == 2 getan hätte, die es schlau genug ist, als nie wahr zu erkennen.

Ich vermute, dass mit vollen 3,5 Optimierungen die ganze Aussage wird nur ausgestreift werden, wie es ziemlich intelligent mit nie wahre Auswertungen ist.

Während ich vielleicht 1==2 kompilieren möchte (um einen Funktionsblock auszuschalten, während ich etwas anderes zum Beispiel teste) möchte ich 1==null nicht.

0

Es sollte ein Kompilierungsfehler sein, da die Typen inkompatibel sind (Werttypen können niemals null sein). Es ist ziemlich traurig, dass es nicht so ist.

+0

Lesen Sie die ganze Frage, ich erkläre, warum es auftritt. Die Frage ist, warum es nicht als Sonderfall behandelt werden kann. – Keith

+0

Wenn ich "Sollen" sage, dann meine ich, dass es einen moralischen Imperativ gibt, nicht, dass ich das vom Compiler erwarte. Die Begründung, die Sie beschreiben, ist nicht im geringsten zwingend; Sie sollten dies zu einem statischen Kompilierungsfehler machen. – DrPizza

1

Das 2.0-Framework führte den Nullwerttyp ein. Auch wenn die Literalkonstante "1" niemals null sein kann, kann ihr zugrunde liegender Typ (int) jetzt in einen nullbaren int-Typ umgewandelt werden. Meine Vermutung ist, dass der Compiler nicht mehr davon ausgehen kann, dass Int-Typen nicht nullbar sind, selbst wenn es sich um eine Literalkonstante handelt. Ich bekomme eine Warnung beim Kompilieren von 2.0:

Warnung 1 Das Ergebnis des Ausdrucks ist immer 'falsch', da ein Wert vom Typ 'int' nie gleich 'null' vom Typ 'int' ist?

+0

Wie ich schon sagte - der Compiler weiß, dass int implizit in int umgewandelt werden kann? und int? kann mit null verglichen werden. Die Warnung ist eine allgemeine für jeden nie zutreffenden Vergleich. 1 == 2 wird die gleiche Warnung ausgeben. – Keith