什么是?
.Net库中的许多方法都以本地代码实现。 那些来自框架本身的标记为[MethodImpl(MethodImplOptions.InternalCall)]
。 那些来自一些非托pipeDLL的标记是[DllImport]
(例如[DllImport("kernel32.dll")]
)。 迄今没有什么不寻常的
但是在为另一个问题写回答时 ,我发现有很多方法用[DllImport("QCall")]
标记。 它们似乎是.Net的内部实现(例如GC._Collect()
)。
我的问题是: [DllImport("QCall")]
是什么意思? [DllImport("QCall")]
和[MethodImpl(MethodImplOptions.InternalCall)]
之间的区别是什么?
这是一种旧思路。 由于CoreCLR现在在GitHub上开源, 如果有人还在寻求答案,这里是官方文件 :
从托pipe调用本地代码
我们有两种从托pipe代码调用CLR的技术。 FCall允许您直接调用CLR代码,并且在操作对象方面提供了很大的灵活性,但是通过正确跟踪对象引用很容易导致GC空洞。 QCall允许您通过P / Invoke调用CLR,并且比FCall更容易误用。 FCalls在托pipe代码中标识为外部方法,并设置了MethodImplOptions.InternalCall位。 QCalls是静态外部方法,看起来像普通的P / Invokes,而是一个名为“QCall”的库。
有一个FCall的小变种叫做HCall(用于Helper调用)来实现JIT助手,用于访问multidimensional array元素,范围检查等等。HCall和FCall唯一的区别是HCall方法不会显示在exception堆栈跟踪中。
然后它继续在子标题:
- 在FCall,QCall,P / Invoke和托pipe代码中写入之间进行select
- QCallfunction行为
用例子:
- QCall示例 – 受pipe零件
- QCall示例 – 非托pipe部分
我问.Net团队中的一些人。
QCalls是对CLR运行时本地方法的调用。 它们的行为与其他[DllImport]
,但速度更快,因为它们对本地方法做了特定的(未logging的)假设,所以它们可以跳过各种编组,GC和exception检查。
InternalCall
是不同的; 这是为了调用在运行时生成的特殊reflection式的东西(这不是很清楚)。
补充@SLaks答案,MethodImplOptions.InternalCall在这里简要描述: ThreadPoolPriority和MethodImplAttribute 。
基本上,InternalCall通知运行时检查自己的命名函数的内部查找表。 该表存在是由于运行时代码中的源文件在编译运行时时显式声明它们。 它有一个实现所有内部调用的函数指针列表:
static ECFunc gGuidFuncs[] = { {FCFuncElement("CompleteGuid", NULL, (LPVOID)GuidNative::CompleteGuid)}, {NULL, NULL, NULL} };
这个声明告诉运行时,被pipe理的Guid.CompleteGuid方法的方法体实际上是本地的C ++ GuidNative :: CompleteGuid函数。 这篇文章不太清楚在这个地方编组的工作方式,但是一般来说这显然是由运行时实现决定的,因为它既是a)声明函数体(依赖于编组格式),b)是否需要编组。