【发布时间】:2018-03-24 15:31:52
【问题描述】:
令我惊讶的是,我今天发现了一个强大的功能。由于它看起来好得令人难以置信,我想确保它不仅仅是由于一些奇怪的巧合而起作用。
我一直认为,当我的 p/invoke(对 c/c++ 库)调用需要一个(回调)函数指针时,我必须在静态 c# 函数上传递一个委托。例如,在下面我总是将 KINSysFn 的委托引用到该签名的静态函数。
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int KINSysFn(IntPtr uu, IntPtr fval, IntPtr user_data );
并使用此委托参数调用我的 P/Invoke:
[DllImport("some.dll", EntryPoint = "KINInit", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int KINInit(IntPtr kinmem, KINSysFn func, IntPtr tmpl);
但现在我刚刚尝试并在实例方法上传递了一个委托,它也可以工作!例如:
public class MySystemFunctor
{
double c = 3.0;
public int SystemFunction(IntPtr u, IntPtr v, IntPtr userData) {}
}
// ...
var myFunctor = new MySystemFunctor();
KINInit(kinmem, myFunctor.SystemFunction, IntPtr.Zero);
当然,我知道在托管代码内部,将“this”对象与实例方法打包在一起以形成相应的委托完全没有技术问题。
但令我惊讶的是,MySystemFunctor.SystemFunction 的“this”对象也找到了通往本机 dll 的方式,它只接受静态函数,不包含任何“this”对象的功能或者和函数一起打包。
这是否意味着任何此类委托都被单独转换(编组?)为静态函数,其中对相应“this”对象的引用以某种方式在函数定义中进行硬编码?如何区分不同的委托实例,例如,如果我有
var myFunctor01 = new MySystemFunctor();
// ...
var myFunctor99 = new MySystemFunctor();
KINInit(kinmem, myFunctor01.SystemFunction, IntPtr.Zero);
// ...
KINInit(kinmem, myFunctor99.SystemFunction, IntPtr.Zero);
这些不能都指向同一个函数。如果我动态创建无限数量的 MySystemFunctor 对象怎么办?每个这样的委托是否在运行时都“展开”/编译为自己的静态函数定义?
【问题讨论】:
-
我想你知道这个问题的答案。您的代码证明了这一点。
-
@DavidHeffernan:您的意思是关于它如何在内部实现的问题?我刚刚提出了一个假设,如果知道它是真的还是有什么我没有想到的,那就太好了。