Frage

Aufgrund eines Fehlers, der in C # 4, das folgende Programm druckt true wurde behoben. (Versuchen Sie es in 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()) { }
}

In VS2008 in Release-Modus, wirft es ein InvalidProgramException. (Im Debug-Modus, es funktioniert gut)

In VS2010 Beta 2, es lässt sich nicht kompilieren (ich habe nicht versucht, Beta 1); Ich habe gelernt, dass die harte Art und Weise

Gibt es eine andere Art und Weise this == null in reinen C #?

zu machen
War es hilfreich?

Lösung

Diese Beobachtung wurde auf Stackoverflow in andere Frage heute früher.

Marc 's große Antwort auf diese Frage zeigt an, dass nach der Spezifikation (Abschnitt 7.5.7), sollten Sie nicht der Lage sein, this in diesem Zusammenhang und die Fähigkeit, den Zugriff auf so in C # 3.0-Compiler ist ein Fehler zu tun. C # 4.0-Compiler verhält sich korrekt nach der Spezifikation (auch in Beta 1, ist dies ein Kompilierung-Fehler):

  

§ 7.5.7 Dieser Zugang

     

A this-Zugriff besteht aus dem reservierten Wort this.

     

this-Zugang:

this
     

A Dieser Zugriff ist nur gestattet, in dem Block einem Instanzkonstruktors, eine Instanzmethode, oder eine Instanz Accessor.

Andere Tipps

Die rohe Dekompilierung (Reflektor ohne Optimierungen) des Debug-Modus binär ist:

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;
    }
}

Die CompilerGenerated Methode macht keinen Sinn; wenn man sich die IL (unten), es ist die Methode auf einem Null-Aufruf 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 

Im Release-Modus wird die lokale Variable ist optimiert entfernt, so dass es auf den Stapel ein nicht-existentes Variable zu drücken versucht.

    L_0000: ldloc.0 
    L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
    L_0006: ret 

(Reflector stürzt ab, wenn es in C # drehen)


Bearbeiten :? Hat jemand (? Eric Lippert), warum der Compiler die ldloc aussendet

Ich habe das hat! (Und bekam Beweis zu)

alt text

Dies ist kein "Bug". Dies ist der Typ System zu missbrauchen. Sie sind nie einen Verweis auf die aktuelle Instanz (this) für jeden in einem Konstruktor übergeben soll.

Ich könnte ein ähnliches „Bug“ erstellen, indem auch eine virtuelle Methode in der Basisklasse Konstruktor aufrufen.

Nur weil Sie können tun etwas Schlimmes bedeutet nicht, es ist ein Fehler , wenn Sie etwas erhalten, indem es.

könnte ich falsch sein, aber ich bin mir ziemlich sicher, wenn Ihr Objekt null es nie ein Szenario, in dem this gilt zu gehen.

Zum Beispiel, wie würden Sie CheckNull nennen?

Derived derived = null;
Console.WriteLine(derived.CheckNull()); // this should throw a NullReferenceException

Nicht sicher, ob dies ist, was Sie suchen

    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);
    }

Beispiel: UserID = CheckForNull (Request.QueryString [ "UserID"], 147);

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top