.Net 2+: pourquoi si (1 == null) ne lève plus une exception de compilateur?
-
09-06-2019 - |
Question
J'utilise int
à titre d'exemple, mais cela s'applique à tout type de valeur dans .Net
Dans .Net 1, ce qui suit lève une exception de compilateur:
int i = SomeFunctionThatReturnsInt();
if( i == null ) //compiler exception here
Maintenant (en .Net 2 ou 3.5) cette exception a disparu.
Je sais pourquoi c'est:
int? j = null; //nullable int
if( i == j ) //this shouldn't throw an exception
Le problème est que parce que int?
est nullable et que i == null
a désormais une conversion implicite vers null
. La syntaxe ci-dessus est la magie du compilateur. Vraiment nous faisons:
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)
Alors maintenant, quand nous faisons <=> nous obtenons:
if( (Nullable<int>) i == null )
Etant donné que C # est en train de faire la logique du compilateur pour calculer cela de toute façon, pourquoi ne peut-il pas être assez intelligent pour ne pas le faire lorsqu'il s'agit de valeurs absolues comme <=>?
La solution
Je ne pense pas qu'il s'agisse d'un problème de compilation en soi ; une valeur entière n'est jamais nulle, mais l'idée de les assimiler n'est pas invalide; c'est une fonction valide qui retourne toujours false. Et le compilateur sait; le code
bool oneIsNull = 1 == null;
compile, mais donne un avertissement au compilateur: The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type '<null>'
.
Donc, si vous souhaitez que l'erreur du compilateur soit corrigée, accédez aux propriétés du projet et activez l'option "Traiter les avertissements comme des erreurs" pour cette erreur. Vous commencerez à les voir à nouveau comme des problèmes de construction.
Autres conseils
Bizarre ... compiler ceci avec VS2008, en ciblant .NET 3.5:
static int F()
{
return 42;
}
static void Main(string[] args)
{
int i = F();
if (i == null)
{
}
}
Je reçois un avertissement du compilateur
warning CS0472: The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type 'int?'
Et il génère l'IL suivant ... qui, vraisemblablement, optimise le JIT
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
Pouvez-vous poster un extrait de code?
Le compilateur continue de générer un avertissement lorsque vous comparez le type non nullable à null, ce qui est exactement ce qu'il devrait être. Votre niveau d'avertissement est peut-être trop bas ou cela a été modifié dans les versions récentes (je ne l'avais fait que dans .net 3.5).
Le framework 2.0 a introduit le type de valeur nullable. Même si la constante littérale & "; 1 &"; ne peut jamais être null, son type sous-jacent (int) peut maintenant être converti en un type Nullable int. Je suppose que le compilateur ne peut plus supposer que les types int ne sont pas nullables, même s'il s'agit d'une constante littérale. Je reçois un avertissement lors de la compilation 2.0:
Avertissement 1 Le résultat de l'expression est toujours 'faux' car une valeur de type 'int' n'est jamais égale à 'null' de type 'int?'
L’avertissement est nouveau (3.5 je pense) - l’erreur est la même que si j’avais fait 1 == 2
, qu’il est assez intelligent pour déceler comme jamais vrai.
Je pense qu'avec les optimisations 3.5 complètes, toute la déclaration sera supprimée, car elle est plutôt intelligente avec des évaluations jamais vraies.
Bien que je puisse vouloir 1==2
compiler (pour désactiver un bloc de fonction pendant que je teste autre chose, par exemple), je ne veux pas 1==null
.
Il devrait s'agir d'une erreur de compilation, car les types sont incompatibles (les types de valeur ne peuvent jamais être nuls). C'est assez triste que ce ne soit pas le cas.