在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 链接):
The extern modifier is used to declare a method that is implemented externally.
但是,方法声明也用 MethodImplOptions.InternalCall
属性修饰,它指示(MSDN 链接):
Specifies an internal call. An internal call is a call to a method that is implemented within the common language runtime itself.
谁能解释这个看似明显的矛盾?
最佳答案
我会评论 leppie's发布,但它变得有点长。
我目前正在研究一个实验性的 CLI 实现。在很多情况下,如果不了解虚拟机内部是如何实现的,就无法实现公开公开的方法(或属性)。一个例子是 OffsetToStringData ,这需要了解内存管理器如何分配字符串。
对于这种没有 C# 代码来表达方法的情况,您可以以一种特殊的方式处理对方法的每次调用内部 JIT 过程。作为此处的示例,在将 call
字节码传递给 native 代码生成器之前,将其替换为 ldc.i4
(加载常量整数)。 InternalCall
标志表示“此方法的主体由运行时本身以特殊方式处理”。可能有也可能没有实际的实现——在我的代码中的几种情况下,调用被视为 intrinsic。由 JIT。
在其他情况下,JIT 可能有特殊的可用信息,允许对方法进行大量优化。一个例子是 Math
方法,即使这些 can be implemented in C# , 指定 InternalCall
使它们成为有效的内在函数具有显着的性能优势。
在 C# 中,方法必须有主体,除非它是 abstract
或 extern
。 extern
表示一般“您可以从 C# 代码调用此方法,但它的主体实际上在其他地方定义。”。当 JIT 到达对 extern
方法的调用时,它会查找在哪里可以找到主体并根据结果以不同的方式表现。
DllImport
属性指示 JIT 生成 P/Invoke stub 以调用 native 代码实现。InternalCall
标志指示 JIT 以自定义方式处理调用。- (还有其他一些,但我没有想出可供使用的示例。)
关于具有 InternalCall 属性的 C# 内部静态外部 - 内部还是外部?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1211462/