MethodImplOptions.InternalCall有什么意义?

时间:2012-06-22 17:19:43

标签: .net clr cil framework-design

BCL中的许多方法都标有[MethodImpl(MethodImplOptions.InternalCall)]属性。 这个indicates表示“方法在公共语言运行时本身内实现”。

以这种方式设计框架的重点是指定了运行时强制实现的显式CIL指令?最终,该属性正在为运行时创建合同义务,但在某种程度上,我觉得这种方式令人困惑,而且并不是很明显。

例如,Math.Pow本来就是这样编写的(请原谅我非正式的C#+ IL和IL本身,如果它不好的话;这只是解释我的观点的一个例子):

public static double Pow(double x, double y)
{
    ldarg.0
    ldarg.1
    pow // Dedicated CIL instruction
    ret
}

而不是当前的方式:

[MethodImpl(MethodImplOptions.InternalCall)]
public static double Pow(double x, double y);

为什么MethodImplOptions.InternalCall存在?

4 个答案:

答案 0 :(得分:9)

我认为一个重要原因是创建一个新的IL指令非常困难,它可能影响很多工具,包括外部工具(ILGenerator,ilasm,ildasm,PEVerify,Reflector,PostSharp,......)

但是创建一个新的InternalCall方法?这几乎就像在C#中编写方法一样简单(我假设,我没有看过Rotor来验证)并且它不会影响任何东西。

这不仅仅是创造它,我认为这同样适用于维护。

答案 1 :(得分:4)

我认为这不会使CLR过于复杂。当我第一次看到CIL时,我不禁注意到与汇编语言的相似之处,更重要的是,有限的指令设置,几乎就像它们直接在处理器上运行一样。

理论上,当CLR JIT是您在帖子中包含的Pow示例代码时,它必须自己发出pow指令的本机代码,因为没有本机指令(或是吗?几年前还没有使用新的x86指令集了。从性能的角度来看,但从实现的角度来看,只需要为pow代码调用mscorlib就好了,而不仅仅是“粘贴”它内联。

或者,他们可以拥有InternalCall的常见mscorlib函数的查找表,并用函数本身调用替换该指令。但话说回来,并非所有InternalCall都如此简单。

我认为这是为了方便而进行的权衡;对于CLR可维护性,更加统一的CLI标准以及为呼叫者提供一定的灵活性。

最重要的是,我还没有开发出CLR,这只是我的头脑。我想我会做的事情。

答案 2 :(得分:3)

该方法是本机的,TRULY native,在Runtime本身中实现。别忘了,毕竟CLR来自C ++。它就像在编译器中一样。在现实世界中,CIL并未真正执行。它被JIT-ted然后像编译器一样由C / C ++运行时执行。 Math.Pow很可能[推测]调用本机C / C ++ math.h pow方法,它的实现定义 - 现在NET和Mono实现了CLR。

在UnityEngine.dll中,[MethodImpl(MethodImplOptions.InternalCall)]用于大多数本机外部方法。然而,这些C ++方法直接使用Mono C ++ CLR库,它们可以以比P / INVOKE本身更亲密的方式与C#合作。并且性能更高(PInvoke隐藏了一些实现细节并且难以理解)

然而,使用[MethodImpl(MethodImplOptions.InternalCall)]的唯一方法是,如果你是CLR运行时本身 - 我只测试了这样的Mono。我不知道是否有可能改变微软的CLR实施,但是对于Mono,您可以自由滥用此功能。

另外,请不要将其与[MethodImpl(MethodImplOptions.Unmanaged)]混为一谈 - 这是完全不同的故事。

有关内部通话以及Mono如何工作的更多信息,请访问:http://www.mono-project.com/docs/advanced/embedding/

免责声明:我与Unity或Mono无关!

答案 3 :(得分:0)

这是一个C#属性(向Mono运行时表明它是对本机方法的调用),它会在.dll中调用与嵌入了Mono运行时的可执行文件链接的.dll中的本机C / C ++代码。函数)或嵌入运行时的可执行文件中(在DLLImport中使用“ __Internal”)。

这是在mono中调用本机代码的两种方法之一,一种是P /调用(使用DLLImport),另一种是内部调用(MethodImplOptions.InternalCall)。 P/invoke provides marshalling,而内部调用仅封送可蓝调类型。参见此处:https://www.mono-project.com/docs/advanced/embedding/

当虚拟机检测到表示内部调用的C#属性时,它将在其配对数据库中查找该函数的名称(由c ++代码构建,例如mono_add_internal_call ("MonoEmbed::gimme", (const void *)gimme)),然后将调用函数的地址。对于Dllimport,它将对.dll进行API调用LoadLibraryGetProcAddress,或者如果__Internal为其自身的模块将hModule = GetModuleHandle(NULL)传递给GetProcAddress < / p>