c++/cli:委托给采用本机参数的托管方法

c++/cli: delegate to managed method taking native argument

我想找到一种方法来调用采用本机参数的引用 class 的方法。创建委托似乎是最明显的选择,但它不适用于此类方法。

请查看以下代码段

#pragma managed(push, off)
struct Native{};
#pragma managed(pop)

#pragma managed(push, on)
ref struct Managed{
    // methods of managed class can take...
    void method1(int){}              // ...value types as an argument
    void method2(System::String^){}  // ...reference types as an argument
    void method3(Native){}           // ...native types as an argument, NICE!
};

int main(array<System::String ^>^ /*args*/) {
    Managed^ m = gcnew Managed;

    auto del1 = gcnew System::Action<int>(m, &Managed::method1);             // ok
    auto del2 = gcnew System::Action<System::String^>(m, &Managed::method2); // ok
    auto del3 = gcnew System::Action<Native>(m, &Managed::method3); // error C3225: generic type argument for 'T' cannot be 'Native', it must be a value type or a handle to a reference type
}
#pragma managed(pop)

错误消息说:

error C3225: generic type argument for 'T' cannot be 'Native', it must be a value type or a handle to a reference type

这并不是说您不能从该方法中创建委托,只是您不能将其表示为 Action<Native>

您可以声明自己的委托类型,或使用可在泛型中使用的有效参数。

使用您自己的委托类型

public delegate void ActionOfNative(Native n);

auto del3 = gcnew ActionOfNative(m, &Managed::method3); // ok

使用可在泛型中使用的有效参数

这确实会改变您传递的参数的语义,但您可以改为传递一个指针。 IntPtr 类型实际上与 void* 相同。您可以将其用作参数类型。不过,您必须自己将 IntPtr 转换回 Native*

void method4(IntPtr ip){Native* np = (Native*)ip.ToPointer(); }

auto del4 = gcnew System::Action<IntPtr>(m, &Managed::method4); // ok

// Here's how you call del4.
Native n;
Native* np = &n;
IntPtr ip = IntPtr(np);

del4(IntPtr(&n));
del4(IntPtr(np));
del4(ip);