(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?

Author: Saeed Amiri, 2009-10-21

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.

 71
Author: Mehrdad Afshari,
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?

 23
Author: SLaks,
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)

texto alt

 10
Author: leppie,
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.

 10
Author: Will,
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
 4
Author: Dan Tao,
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);

 -1
Author: Scott and the Dev Team,
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