2

我正在包装一个使用 MonoDevelop 进行回调的块的 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 获取托管用户类。相反,我得到一个指向非托管用户类的指针。所以它是这样工作的:

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.它要求用户明确声明“不安全”,属性(无法阻止)并实际将指针传递给包装类,这样他/她就会有一个“用户”的漂亮 C# 接口。

我试过这样做:在调用 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 上不起作用。

除了让用户专门包装他/她自己不满足我的指针之外,我找不到任何其他方法来解决它。考虑过使用静态数组来存储回调,但我无法真正将返回的内部回调与我想要调用的回调匹配(或者我可以吗?)

有什么建议么?:)

编辑:我想我只是想在原始回调和调用者之间添加一个回调桥——就像一个中间人。但我不能用匿名代表来做这件事。有没有办法做到这一点?

4

0 回答 0