(Esta == null) em C #!
-
05-07-2019 - |
Pergunta
Devido a um bug que foi corrigido em C # 4, o seguinte programa imprime true
. (Experimente-o em LINQPad)
void Main() { new Derived(); }
class Base {
public Base(Func<string> valueMaker) { Console.WriteLine(valueMaker()); }
}
class Derived : Base {
string CheckNull() { return "Am I null? " + (this == null); }
public Derived() : base(() => CheckNull()) { }
}
Em VS2008 no modo de versão, ele lança uma InvalidProgramException. (No modo de depuração, ele funciona bem)
Em VS2010 Beta 2, que não compila (eu não tentar Beta 1); Eu aprendi isso da pior maneira
Existe alguma outra maneira de fazer this == null
em puro C #?
Solução
Esta observação foi publicado em StackOverflow em outra pergunta hoje cedo.
Marc 's grande resposta para essa pergunta indica que, de acordo com a especificação (seção 7.5.7), você não deve ser capaz de acesso this
nesse contexto e a capacidade de fazê-lo em C # 3.0 do compilador é um bug. C # 4.0 do compilador está se comportando corretamente de acordo com as especificações (mesmo no Beta 1, este é um erro de tempo de compilação):
§ 7.5.7 Este acesso
A este acesso consiste na
this
palavra reservada.este acesso:
this
A este acesso é permitido apenas no bloco de um construtor de instância, um método de instância, ou um acessor exemplo.
Outras dicas
A descompilação raw (Refletor sem otimizações) do binário modo de depuração é:
private class Derived : Program.Base
{
// Methods
public Derived()
{
base..ctor(new Func<string>(Program.Derived.<.ctor>b__0));
return;
}
[CompilerGenerated]
private static string <.ctor>b__0()
{
string CS$1$0000;
CS$1$0000 = CS$1$0000.CheckNull();
Label_0009:
return CS$1$0000;
}
private string CheckNull()
{
string CS$1$0000;
CS$1$0000 = "Am I null? " + ((bool) (this == null));
Label_0017:
return CS$1$0000;
}
}
método O CompilerGenerated não faz sentido; se você olhar para a IL (abaixo), que está chamando o método em um nulo string (!).
.locals init (
[0] string CS$1$0000)
L_0000: ldloc.0
L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
L_0006: stloc.0
L_0007: br.s L_0009
L_0009: ldloc.0
L_000a: ret
No modo Release, a variável local é otimizado distância, por isso tenta empurrar uma variável inexistente para a pilha.
L_0000: ldloc.0
L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
L_0006: ret
(Reflector falha quando transformando-o em C #)
Editar :? Alguém (? Eric Lippert) sabe por que o compilador emite o ldloc
Eu tive isso! (E prova obtida também)
Este não é um "bug". Isto é você abusar do sistema tipo. Que nunca se deve passar uma referência para a instância atual (this
) para qualquer um dentro de um construtor.
Eu poderia criar um "bug" semelhante ao chamar um método virtual dentro do construtor da classe base também.
Só porque você pode fazer algo ruim não significa que é um bug quando você começa pouco por ela.
Eu posso estar errado, mas eu tenho certeza que se o seu objeto é null
há nunca vai ser um cenário onde this
aplica.
Por exemplo, como você chamaria CheckNull
?
Derived derived = null;
Console.WriteLine(derived.CheckNull()); // this should throw a NullReferenceException
Não sei se isso é o que você está procurando
public static T CheckForNull<T>(object primary, T Default)
{
try
{
if (primary != null && !(primary is DBNull))
return (T)Convert.ChangeType(primary, typeof(T));
else if (Default.GetType() == typeof(T))
return Default;
}
catch (Exception e)
{
throw new Exception("C:CFN.1 - " + e.Message + "Unexpected object type of " + primary.GetType().ToString() + " instead of " + typeof(T).ToString());
}
return default(T);
}
exemplo: IDUtilizador = CheckForNull (Request.QueryString [ "ID de utilizador"], 147);