【问题标题】:C# internal static extern with InternalCall attribute - internal or external?具有 InternalCall 属性的 C# 内部静态外部 - 内部还是外部?
【发布时间】:2010-11-15 17:41:04
【问题描述】:

在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链接):

指定内部调用。一个 内部调用是对方法的调用 这是在公共范围内实施的 语言运行时本身。

谁能解释这个看似明显的矛盾?

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    InternalCall 表示由框架提供。

    extern 说你没有提供代码。

    extern 可用于 2 种一般情况,如上述,或与 p/invoke 一起使用。

    使用 p/invoke,您只需告诉方法从哪里获取实现。

    【讨论】:

    • @leppie - 我希望我可以将您和 280Z28 的答案都标记为已接受,因为您都是正确的。不过,我觉得280Z28的回答说得更清楚一些,帮助我更好地理解,但是,非常感谢你的努力。
    • 没问题,我的积分已经够多了,我也给他加分吧:)
    【解决方案2】:

    我本来会在leppie's 帖子上发表评论,但它有点长。

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

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

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

    在 C# 中,方法必须有一个主体,除非它是 abstract 或 extern。 extern 表示一般的“您可以从 C# 代码中调用此方法,但它的主体实际上是在其他地方定义的。”。当 JIT 调用 extern 方法时,它会查找在哪里可以找到主体,并根据结果以不同的方式运行。

    • DllImport 属性指示 JIT 创建 P/Invoke 存根以调用本机代码实现。
    • InternalCall 标志指示 JIT 以自定义方式处理调用。
    • (还有一些其他的,但我没有想到可以使用的示例。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-01
      • 1970-01-01
      • 2011-06-26
      相关资源
      最近更新 更多