令我惊讶的是,今天我发现了一个强大的功能。由于看起来太美好而难以置信,我想确保它不仅仅是因为某种奇怪的巧合而起作用。
我一直认为,当我的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,该dll仅接受静态函数,并不包含任何关于“this”对象或将其与函数一起打包的设施。
这是否意味着任何此类委托都会被单独转换(编组?)为静态函数,其中对相应“this”对象的引用在函数定义中以某种方式硬编码?否则,如何区分不同的委托实例,例如,如果我有:
var myFunctor01 = new MySystemFunctor();
// ...
var myFunctor99 = new MySystemFunctor();
KINInit(kinmem, myFunctor01.SystemFunction, IntPtr.Zero);
// ...
KINInit(kinmem, myFunctor99.SystemFunction, IntPtr.Zero);
这些不能都指向同一个函数。如果我动态创建了无限数量的MySystemFunctor对象呢?每个这样的代理在运行时是否都会“展开”/编译为自己的静态函数定义?