.Net 2+:por que if( 1 == null ) não lança mais uma exceção do compilador?
-
09-06-2019 - |
Pergunta
estou a usar int
como exemplo, mas isso se aplica a qualquer tipo de valor em .Net
No .Net 1, o seguinte geraria uma exceção do compilador:
int i = SomeFunctionThatReturnsInt();
if( i == null ) //compiler exception here
Agora (no .Net 2 ou 3.5) essa exceção desapareceu.
Eu sei por que isso acontece:
int? j = null; //nullable int
if( i == j ) //this shouldn't throw an exception
O problema é que porque int?
é anulável e int
agora tem uma conversão implícita para int?
.A sintaxe acima é mágica do compilador.Na verdade estamos fazendo:
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)
Então agora, quando fazemos i == null
Nós temos:
if( (Nullable<int>) i == null )
Dado que o C# está fazendo a lógica do compilador para calcular isso de qualquer maneira, por que não pode ser inteligente o suficiente para não fazê-lo ao lidar com valores absolutos como null
?
Solução
Eu não acho que isso seja um problema do compilador por si só;um valor inteiro nunca é nulo, mas a ideia de igualá-los não é inválida;é uma função válida que sempre retorna falso.E o compilador sabe;o código
bool oneIsNull = 1 == null;
compila, mas dá um aviso ao compilador: The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type '<null>'
.
Portanto, se você quiser que o erro do compilador volte, vá para as propriedades do projeto e ative 'tratar avisos como erros' para esse erro, e você começará a vê-los como problemas de quebra de compilação novamente.
Outras dicas
Chance ...compilando isso com o VS2008, visando o .NET 3.5:
static int F()
{
return 42;
}
static void Main(string[] args)
{
int i = F();
if (i == null)
{
}
}
Recebo um aviso do compilador
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 gera o seguinte IL ...que presumivelmente o JIT irá otimizar
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
Você pode postar um trecho de código?
O compilador ainda gera um aviso quando você compara o tipo não anulável com o nulo, que é exatamente como deveria ser.Pode ser que seu nível de aviso esteja muito baixo ou tenha sido alterado em versões recentes (só fiz isso no .net 3.5).
A estrutura 2.0 introduziu o tipo de valor anulável.Mesmo que a constante literal "1" nunca possa ser nula, seu tipo subjacente (int) agora pode ser convertido em um tipo int Nullable.Meu palpite é que o compilador não pode mais assumir que os tipos int não são anuláveis, mesmo quando é uma constante literal.Recebo um aviso ao compilar o 2.0:
Aviso 1 O resultado da expressão é sempre 'false' pois um valor do tipo 'int' nunca é igual a 'null' do tipo 'int?'
O aviso é novo (3,5, eu acho) - o erro é o mesmo que se eu tivesse feito 1 == 2
, o que é inteligente o suficiente para identificar como nunca sendo verdade.
Suspeito que, com otimizações completas de 3,5, toda a afirmação será simplesmente eliminada, pois é bastante inteligente com avaliações nunca verdadeiras.
Embora eu possa querer 1==2
compilar (para desligar um bloco de função enquanto testo outra coisa, por exemplo) não quero 1==null
para.
Deveria ser um erro em tempo de compilação, porque os tipos são incompatíveis (os tipos de valor nunca podem ser nulos).É muito triste que não seja.