C# 为什么这样做有效?在没有实例的情况下从IL执行方法
我看了一遍,这段代码让我想了想:C# 为什么这样做有效?在没有实例的情况下从IL执行方法,c#,.net,il,C#,.net,Il,我看了一遍,这段代码让我想了想: public class Program { delegate void HelloDelegate(Strange bar); [STAThread()] public static void Main(string[] args) { Strange bar = null; var hello = new DynamicMethod("ThisIsNull", type
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);
}
}
}
我确实理解代码的作用,但我不理解它为什么工作。这不就像做null.Foo()
?它的工作原理好像Foo()
是静态的,而这是被调用的:奇怪的.Foo()代码>
你能告诉我我缺少什么吗?这个
是作为一个普通参数实现的;您的代码只是将null
作为此参数传递
这通常会引发NullReferenceException
的唯一原因是,通常使用CallVirt
指令调用方法,该指令对this
参数执行vtable查找,并在其为null时引发
如果使用调用
,即使此
为空,该方法也会执行得非常好,尽管该方法本身可能会在以后抛出。这非常有趣!非常感谢您的回答:)我不知道opcode.Callvirt
和opcode.Call
之间的区别。一个小小的搜索引导我做到了这一点:事实上,在上面的代码中,更改il.Emit(OpCodes.Call,foo)代码>到il.Emit(opcode.Callvirt,foo)代码>引发异常。再次感谢您+1.如果有兴趣,可以更详细地讨论使用callvirt
的一些原因。顺便说一句,这就是编译器使用call
实现base.Foo()的原因代码>调用在技术上是违反规范的:C#规范要求base.Foo()
如果this==null
则抛出NullReferenceException
。(当然,如果有人真的想解决这个问题,那么解决办法可能是修改规范。)@hvd:this
有没有任何规范合法的方法可以让它null
?@SLaks当然,可以从用C#以外的语言实现的另一种方法调用它。C#规范不要求使用非C语言编写的方法来遵守C#的规则,.NET的一大特点是支持不同语言之间的互操作性。这个问题是获取This==null
的一种合法方法。