c# - 在 std::function 中包装委托(delegate)?

标签 c# c++ .net c++-cli clr

我有一个 native 非托管 C++ 库,我想将其包装在托管 C++ 类中,以提供干净且类型安全的方式来从 C# 访问非托管类,而无需执行 PInvoke。

我尝试包装的方法之一具有以下签名:

void Unmanaged::login(
  const std::wstring& email,
  const std::wstring& password,
  std::function<void()> on_success,
  std::function<void(int, const std::wstring&)> on_error);

然而,尝试将其包装起来并不容易。显而易见的方法:

public delegate void LoginSuccess();
public delegate void LoginFailed(int, String^);

void Wrapper::login(String ^ email, String ^ password, LoginSuccess ^ onSuccess, LoginFailed ^ onError)
{
    unmanaged->login(convert_to_unmanaged_string(email), convert_to_unmanaged_string(password), [onSuccess]() {onSuccess(); }, [](int code, const std::wstring& msg) {onError(code,convert_to_managed_string(msg))});
}

失败,因为托管 C++ 不允许(本地)lambda(在成员中)。

我知道我可以使用 Marshal::GetFunctionPointerForDelegate 获取指向委托(delegate)的 native 指针,但我仍然需要提供一个“中间件”来在托管/非托管类型(例如 std::wstring)之间进行转换。

是否有比完全使用托管 C++ 更好的方法?

最佳答案

您的代码无法编译,因为您无法在 native lambda 中捕获托管对象。但是在 gcroot 类的帮助下,您可以轻松地将托管对象包装在非托管对象中:

您需要这些 header :

#include <vcclr.h>
#include <msclr/marshal_cppstd.h>

这是封装代码:

static void managedLogin(String^ email, String^ password, LoginSuccess^ onSuccess, LoginFailed^ onError)
{
    gcroot<LoginSuccess^> onSuccessWrapper(onSuccess);
    gcroot<LoginFailed^> onErrorWrapper(onError);

    Unmanaged::login(
        msclr::interop::marshal_as<std::wstring>(email),
        msclr::interop::marshal_as<std::wstring>(password),
        [onSuccessWrapper]() {
            onSuccessWrapper->Invoke();
        },
        [onErrorWrapper](int code, const std::wstring& message) {
            onErrorWrapper->Invoke(code, msclr::interop::marshal_as<String^>(message));
        }
    );
}

public ref class Wrapper
{
public:
    static void login(String ^ email, String ^ password, LoginSuccess ^ onSuccess, LoginFailed ^ onError)
    {
        managedLogin(email, password, onSuccess, onError);
    }
};

gcroot对象包装 System::Runtime::InteropServices::GCHandle ,这将使托管对象保持事件状态。这是一个可以在 lambda 中捕获的非托管类。了解这一点后,剩下的就很简单了。

出于某种原因,如果您尝试在成员 函数中使用 lambda,编译器会报错,但在自由函数中使用 lambda 完全没问题。去图吧。

关于c# - 在 std::function 中包装委托(delegate)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38147515/

相关文章:

c# - Web 服务无法使用 GAC 中的类型创建类型错误

c++ - 如何打印 Qt 对话框或窗口?

java - 如何将 C++ 集成到 Android Java 应用程序中?

c# - ASP.NET 图表控件透明度

c# - EmguCV - 运动检测不返回角度

c++ - Clang 错误 – 编译器错误或缺少一些细节?

javascript - .Net windows 应用程序 WebBrowser/Google Maps API v3

c# - 修改 ASP.NET MVC 2 中的 HTML Helpers

.net - 什么时候应该使用结构而不是类?

c# - WebMethod 无法捕获通过 ajax 发送的对象