(Dies == null) in C #!
-
05-07-2019 - |
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 #?
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)
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);