具有InternalCall属性的C#内部静态extern - 内部还是外部?

时间:2009-07-31 09:10:07

标签: c# .net

在我another question中,我发表了一条评论,表明.NET框架的Array.Copy方法使用了非托管代码。我用Reflector挖掘并发现Array.Copy方法重载的签名之一定义如下:

[MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
internal static extern void Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length, bool reliable);
看着这个之后,我有点困惑。我混淆的原因是extern修饰符,意思是(MSDN链接):

  

extern修饰符用于声明   一种实现的方法   外部

但是,方法声明也使用MethodImplOptions.InternalCall属性进行修饰,该属性表示(MSDN链接):

  

指定内部呼叫。一个   内部调用是对方法的调用   这是在共同体内实施的   语言运行时本身。

任何人都可以解释这个看似明显的矛盾吗?

2 个答案:

答案 0 :(得分:49)

我会对leppie's帖子发表评论,但这有点长。

我目前正在进行实验性CLI实施。在许多情况下,如果不了解内部如何实施虚拟机,则无法实现公开的方法(或属性)。一个例子是OffsetToStringData,它需要知道内存管理器如何分配字符串。

对于这样的情况,如果没有表示方法的C#代码,您可以以特殊的方式将对方法的每次调用视为 internal 到JIT进程。作为示例,在将call字节代码传递给本机代码生成器之前,将ldc.i4字节代码替换为InternalCall(加载常量整数)。 Math标志表示“运行时本身以特殊方式处理此方法的主体。”可能有也可能没有实际的实现 - 在我的代码中的几种情况下,JIT将调用视为intrinsic

在其他情况下,JIT可能有特殊信息,可以对方法进行大量优化。一个例子是InternalCall方法,即使这些can be implemented in C#,指定abstract以使其有效地具有内在函数也具有显着的性能优势。

在C#中,除非externextern,否则方法必须包含正文。 extern表示一般“你可以用C#代码调用这个方法,但它的主体实际上是在其他地方定义的。”当JIT到达DllImport方法的调用时,它会查找找到正文的位置,并根据结果以不同的方式运行。

  • InternalCall属性指示JIT创建P / Invoke存根以调用本机代码实现。
  • {{1}}标志指示JIT以自定义方式处理呼叫。
  • (还有一些其他人,但我没有让他们使用的例子。)

答案 1 :(得分:16)

InternalCall表示框架提供。

extern表示您没有提供代码。

extern可用于两种一般情况,如上所述,或使用p / invoke。

使用p / invoke,您只需告诉方法获取实现的位置。