我正在使用Mono -velop包装一个Obj-C api,它使用块进行回调。我设法将我的C#委托连接到Objective-C中的一个块,只要我用[MonoPInvokeCallback]装饰它们就可以正常工作,因此它可以编译AOT。
在块返回类实例之前,这一切都很好。这让我回到C#指向类的指针(我的实现中的IntPtr)。通常当我从Obj-C调用的方法返回此指针时,我用自己的托管类包装句柄并从那里调用所有方法 - 为包装句柄提供一个很好的C#接口。在这种特定的情况下,IntPtr被直接调用到用户自制的回调中,所以我没有机会很好地包装它。
delegate void GetUserCallback(User user);
//User callback
[MonoPInvokeCallback (typeof (GetUserCallback))]
void PrintUserName(User user) {
Console.WriteLine(user.name);
}
void GetUserById (int id, GetUserCallback callback) {
ApiGetUserById(id, callback);
}
现在这不起作用,因为我无法从Objective-C获得托管的User类。我改为获得一个指向非托管User类的指针。所以它的工作原理如下:
delegate void GetUserCallbackPtr(IntPtr userPtr);
//User callback
[MonoPInvokeCallback (typeof (GetUserCallbackPtr))]
unsafe void PrintUserName(IntPtr userPtr) {
User user = new User(userPtr);
Console.WriteLine(user.name);
}
void GetUserById (int id, GetUserCallbackPtr callback) {
ApiGetUserById(id, callback);
}
这可行,但它有两种方面很难看: 1.它要求用户专门声明“unsafe”,属性(无法阻止)并实际将指针传递给包装类,这样他/她就会有一个很好的C#接口“User”。
我试过这样做: 在调用API并提供回调的方法中,创建一个新的回调函数,它获取IntPtr,包装它,并使用它来调用原始函数 - 例如:
delegate void GetUserCallback(User user);
delegate void GetUserCallbackPtr(IntPtr userPtr);
//User callback
void PrintUserName(User user) {
Console.WriteLine(user.name);
}
void GetUserById (int id, GetUserCallback callback) {
ApiGetUserById(id, InnerCallback);
}
[MonoPInvokeCallback (typeof (GetUserCallbackPtr))]
void InnerCallback(IntPtr userPtr) {
// How do I run the original "callback" from here?
}
无法运行回调。所以我尝试了匿名委托(或lambda):
delegate void GetUserCallback(User user);
delegate void GetUserCallbackPtr(IntPtr userPtr);
//User callback
void PrintUserName(User user) {
Console.WriteLine(user.name);
}
void GetUserById (int id, GetUserCallback callback) {
ApiGetUserById(id, delegate(IntPtr userPtr) {
callback(userPtr);
});
}
这也不起作用,因为匿名委托没有使用MonoPInvokeCallback属性进行修饰,而且它的编译JIT在iphone上不起作用。
我找不到任何其他方法来解决它,除了让用户专门包装他/她自己不满足我的指针。考虑使用静态数组来存储回调,但我无法将返回的内部回调与我想要调用的回调相匹配(或者我可以吗?)
有什么建议吗? :)
编辑:我想我只是想在原始回调和来电者之间添加一个回调桥 - 就像中间人一样。但我不能与匿名代表这样做。有没有办法做到这一点?