C#内部静态外部与​​InternalCall属性 - 内部还是外部?静态、属性、InternalCall

2023-09-02 21:43:29 作者:梁山伯揍英台

在another问题我问,评论出现,表明.NET框架的 Array.Copy 方法使用非托管code。我去反射挖掘,发现签名的一个 Array.Copy 方法重载的定义是这样:

In another question I asked, a comment arose indicating that the .NET framework's Array.Copy method uses unmanaged code. I went digging with Reflector and found the signature one of the Array.Copy method overloads is defined as so:

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

After looking at this, I'm slightly confused. The source of my confusion is the extern modifier which means (MSDN link):

该extern修饰符用于声明   即实施的方法   外部。

The extern modifier is used to declare a method that is implemented externally.

然而,在方法声明还装饰有一个 MethodImplOptions.InternalCall 属性,这表明(MSDN链接):

However, the method declaration is also decorated with a MethodImplOptions.InternalCall attribute, which indicates (MSDN link):

指定一个内部电话。一个   内部呼叫是一种方法,   即在共同实现   语言运行时本身。

Specifies an internal call. An internal call is a call to a method that is implemented within the common language runtime itself.

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

Can anyone explain this seemingly apparent contradiction?

推荐答案

我刚才评论leppie's后期,但它变得有点长。

I would have just commented on leppie's post, but it was getting a bit long.

我目前工作的一个实验性的CLI实现。有很多情况,其中一个公共公开方法(或属性)不能未经如何在虚拟机内部实现知识来实现​​。一个例子是OffsetToStringData,这需要如何内存管理器分配串知识

I'm currently working on an experimental CLI implementation. There are many cases where a publicly exposed method (or property) can't be implemented without knowledge of how the virtual machine is implemented internally. One example is OffsetToStringData, which requires knowledge of how the memory manager allocates strings.

有关这样的情况下,如果没有C#code到EX preSS的方法,你可以把每次调用该方法以特殊的方式的的内部应用于JIT过程。作为这里的一个例子,取代之前的通话 ldc.i4 (负载不变整数)字节code它传递给本地code发电机。该 InternalCall 标记表示这种方法的主体在运行时本身就是一种特殊的方式处理。可能有也可能没有实际的实现 - 在一些情况下,在我的code通话将被视为内在由JIT。

For cases like this, where there is no C# code to express the method, you can treat each call to the method in a special way internal to the JIT process. As an example here, replacing the call byte code with a ldc.i4 (load constant integer) before passing it to the native code generator. The InternalCall flag means "The body of this method is treated in a special way by the runtime itself." There may or may not be an actual implementation - in several cases in my code the call is treated as an intrinsic by the JIT.

有其他情况下JIT可以具有允许的方法的重优化可用特殊信息。一个例子是数学方法,在这里即使这些可以用C#,指定 InternalCall 来使他们有效地内在有显著的性能优势。

There are other cases where the JIT may have special information available that allows heavy optimization of a method. One example is the Math methods, where even though these can be implemented in C#, specifying InternalCall to make them effectively intrinsics has significant performance benefits.

在C#中,方法必须有一个机构,除非它是摘要的extern 。该的extern 是指一般的您还可以从C#code这种方法,但它的身体实际上是在其他地方定义。当JIT达到一个电话给的extern 方法,查找在哪里找到的身体和行为在每个结果不同的方式。

In C#, a method has to have a body unless it is abstract or extern. The extern means a general "You can call this method from C# code, but the body of it is actually defined elsewhere.". When the JIT reaches a call to an extern method, it looks up where to find the body and behaves in different ways per the result.

的DllImport 属性指示JIT作出的P / Invoke存根调用本机code实现。 的 InternalCall 标志指示JIT治疗以自定义的方式调用。 (也有一些人​​,但我没有例子把我的头供他们使用的顶部。) The DllImport attribute instructs the JIT to make a P/Invoke stub to call a native code implementation. The InternalCall flag instructs the JIT to treat the call in a self-defined way. (There are some others, but I don't have examples off the top of my head for their use.)