(esto = = null) en C#!
Debido a un error que se solucionó en C# 4, el siguiente programa imprime true
. (Pruébalo en 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()) { }
}
En VS2008 en modo Release, lanza una InvalidProgramException. (En modo de depuración, funciona bien)
En VS2010 Beta 2, no compila (no probé Beta 1); aprendí que de la manera difícil
¿Hay alguna otra forma de hacer this == null
en C#puro?
6 answers
Esta observación se ha publicado en StackOverflow en otra pregunta hoy temprano.
La gran respuesta de Marc a esa pregunta indica que de acuerdo con la especificación (sección 7.5.7), no debería poder acceder a this
en ese contexto y la capacidad de hacerlo en el compilador C# 3.0 es un error. El compilador de C # 4.0 se comporta correctamente de acuerdo con la especificación (incluso en Beta 1, este es un error de tiempo de compilación):
§ 7.5.7 Esto acceso
A este-acceso consiste en la palabra reservada
this
.este acceso:
this
A this-access solo está permitido en el bloque de un constructor de instancia, un método de instancia o un accessor de instancia.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:32
La descompilación raw (Reflector sin optimizaciones) del binario de modo de depuración es:
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;
}
}
El método CompilerGenerated no tiene sentido; si nos fijamos en el IL (abajo), está llamando al método en una cadena null (!).
.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
En el modo Release, la variable local se optimiza lejos, por lo que intenta empujar una variable no existente a la pila.
L_0000: ldloc.0
L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
L_0006: ret
(El reflector se bloquea al convertirlo en C#)
EDIT: ¿Alguien (Eric ¿Lippert?) saber por qué el compilador emite el ldloc
?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-21 16:24:39
He tenido eso! (y tiene pruebas también)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-08 14:16:27
Esto no es un "error". Este es usted abusando del sistema de tipos. Se supone que nunca debe pasar una referencia a la instancia actual (this
) a nadie dentro de un constructor.
Podría crear un "bug" similar llamando a un método virtual dentro del constructor de clase base también.
Solo porque puede hacer algo malo no significa que sea un error cuando te muerde.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-21 13:09:22
Podría estar equivocado, pero estoy bastante seguro de que si su objeto es null
nunca va a haber un escenario donde this
se aplica.
Por ejemplo, ¿cómo llamarías a CheckNull
?
Derived derived = null;
Console.WriteLine(derived.CheckNull()); // this should throw a NullReferenceException
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-21 12:59:31
No estoy seguro de si esto es lo que estás buscando
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);
}
Ejemplo: userId = CheckForNull(Request.QueryString ["userId"], 147);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-07 16:16:40