ich durch What's the strangest corner case you've seen in C# or .NET? suchen, und dieser Code gemacht denken, mich ein wenig:Warum funktioniert das? Ausführen von Verfahren von IL ohne Beispiel
public class Program
{
delegate void HelloDelegate(Strange bar);
[STAThread()]
public static void Main(string[] args)
{
Strange bar = null;
var hello = new DynamicMethod("ThisIsNull",
typeof(void), new[] { typeof(Strange) },
typeof(Strange).Module);
ILGenerator il = hello.GetILGenerator(256);
il.Emit(OpCodes.Ldarg_0);
var foo = typeof(Strange).GetMethod("Foo");
il.Emit(OpCodes.Call, foo);
il.Emit(OpCodes.Ret);
var print = (HelloDelegate)hello.CreateDelegate(typeof(HelloDelegate));
print(bar);
Console.ReadLine();
}
internal sealed class Strange
{
public void Foo()
{
Console.WriteLine(this == null);
}
}
}
Ich verstehe, was der Code tut, aber ich verstehe nicht, warum es funktioniert. Ist das nicht so, null.Foo()
zu tun? Es funktioniert so, als ob Foo()
statisch ist, und dies wird stattdessen aufgerufen: Strange.Foo();
.
Würden Sie mir bitte sagen, was ich vermisse?
Das ist sehr, sehr interessant! Vielen Dank für Ihre Antwort :) Mir war der Unterschied zwischen 'OpCodes.Callvirt' und' OpCodes.Call' nicht bewusst. Eine kleine Suche führte mich dazu: http://blogs.msdn.com/b/ericgu/archive/2008/07/02/why-does-c-always-use-callvirt.aspx Und zwar im Code oben, ändert 'il.Emit (OpCodes.Call, foo);' zu 'il.Emit (OpCodes.Callvirt, foo);' löst eine Ausnahme aus. Nochmals vielen Dank! – user3439065
+1. [Warum erzeugt der C# -Compiler einen Methodenaufruf, um die BaseClass-Methode in IL aufzurufen] (http://stackoverflow.com/questions/10219188/why-does-c-sharp-compiler-produce-method-call-to-call-baseclass- method-in-il? rq = 1) diskutiert einige Gründe für die Verwendung von 'callvirt' in ein wenig mehr Details, wenn man interessiert ist. –
Dies ist der Grund, warum der Aufruf des Aufrufs des Compilers zum Implementieren von base.Foo(); -Anrufen technisch eine Spec-Verletzung ist: Die C# -Spezifikation erfordert 'base.Foo();', um 'NullReferenceException' if' zu werfen dies == null'. (Natürlich, wenn jemand wirklich daran interessiert ist, das Problem zu beheben, wird das Problem wahrscheinlich darin bestehen, die Spezifikation zu ändern.) – hvd