我一直认为this在实例方法体内是不可能的.以下简单的程序表明它是可能的.这是一些记录在案的行为?
class Foo
{
public void Bar()
{
Debug.Assert(this == null);
}
}
public static void Test()
{
var action = (Action)Delegate.CreateDelegate(typeof (Action), null, typeof(Foo).GetMethod("Bar"));
action();
}
Run Code Online (Sandbox Code Playgroud)
UPDATE
我同意答案,说明这种方法的记录方式.但是,我真的不明白这种行为.特别是因为它不是C#的设计方式.
我们收到了某人的报告(很可能是一个使用C#的.NET组(当时认为它还没有命名为C#))谁编写了一个在空指针上调用方法的代码,但是他们没有得到一个例外,因为该方法没有访问任何字段(即"this"为null,但方法中没有使用它).那个方法然后调用另一个方法,它确实使用了这一点并引发了一个异常,随后出现了一些令人头疼的问题.在他们弄清楚之后,他们给我们发了一张关于它的说明.我们认为能够在null实例上调用方法有点奇怪.Peter Golde做了一些测试,看看总是使用callvirt的性能影响是什么,它足够小,我们决定做出改变.
http://blogs.msdn.com/b/ericgu/archive/2008/07/02/why-does-c-always-use-callvirt.aspx
Mar*_*wul 23
因为你传递null到firstArgument的Delegate.CreateDelegate
所以你要在null对象上调用实例方法.
http://msdn.microsoft.com/en-us/library/74x8f551.aspx
如果firstArgument是空引用而method是实例方法,则结果取决于委托类型类型和方法的签名:
如果类型的签名明确包含方法的隐藏的第一个参数,则表示委托表示开放实例方法.调用委托时,参数列表中的第一个参数将传递给方法的隐藏实例参数.
如果方法和类型的签名匹配(即,所有参数类型都是兼容的),则表示委托被空引用关闭.调用委托就像在null实例上调用实例方法一样,这不是特别有用的事情.
Alo*_*aus 12
当您使用调用IL指令或委托方法时,您确实可以调用方法.如果您尝试访问将为您提供您所寻求的NullReferenceException的成员字段,则仅设置此booby陷阱.
尝试
int x;
public void Bar()
{
x = 1; // NullRefException
Debug.Assert(this == null);
}
Run Code Online (Sandbox Code Playgroud)
BCL甚至包含显式的这个== null检查,以帮助调试不使用callvirt(如C#)的语言.有关更多信息,请参阅此问题.
例如,String类具有此类检查.除了你不会在C#这样的语言中看到它们的需要之外,没有什么是神秘的.
// Determines whether two strings match.
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public override bool Equals(Object obj)
{
//this is necessary to guard against reverse-pinvokes and
//other callers who do not use the callvirt instruction
if (this == null)
throw new NullReferenceException();
String str = obj as String;
if (str == null)
return false;
if (Object.ReferenceEquals(this, obj))
return true;
return EqualsHelper(this, str);
}
Run Code Online (Sandbox Code Playgroud)
this是一个参考,所以null从类型系统的角度来看它是没有问题的.
你可能会问为什么NullReferenceException没有抛出.当CLR抛出该异常情况的完整列表记录.您的案例未列出.是的,它是一个callvirt,但是Delegate.Invoke(见这里)而不是Bar,所以this引用实际上是你的非null委托!
您看到的行为对CLR有一个有趣的实现后果.委托有一个很常见的Target属性(对应于你的this引用)null,即委托是静态的(想象Bar是静态的).现在,有一个私有支持字段,称为该属性_target.是否_target包含静态委托的null? 不,不. 它包含对委托本身的引用.为什么不null?因为null是委托的合法目标,如您的示例所示,并且CLR没有两种null指针来区分静态委托.
这一部分的trivium表明,对于委托,实例方法的空目标是没有事后的想法.你可能仍在问最终的问题:但为什么必须得到他们的支持?
早期的CLR有一个雄心勃勃的计划,即使对于宣誓的C++开发人员来说,成为首选平台,这个目标首先是使用托管C++,然后是C++/CLI.一些过于具有挑战性的语言特性被省略了,但是在没有实例的情况下支持实例方法执行并没有什么真正的挑战,这在C++中是完全正常的.包括代表支持.
因此,最终的答案是:因为C#和CLR是两个不同的世界.
更好的阅读和更好的阅读,以显示允许空实例的设计,即使在非常自然的C#语法上下文中也显示其痕迹.
| 归档时间: |
|
| 查看次数: |
4574 次 |
| 最近记录: |