托管代码的C ++ / CLI托管类成员回调

时间:2014-03-10 15:08:50

标签: delegates c++-cli

我正在设计一个使用用户代码提供的回调函数的C ++ / CLR类。

如果回调函数是空闲的(即不是类的成员),这非常有效。它与纯C ++几乎相同。

以下是一些效果良好的示例代码:

ref class ClassThatUsesCallback
{
public:
    typedef void (*callback_t)( String^ );
    void setCallback( callback_t pfun )
    {
        myCallback = pfun;
    }
    void Run()
    {
        if( myCallback != nullptr ) {
            myCallback("This is a test");
        }
    }
private:
    callback_t myCallback;
};

void FreeFunction( String^ s )
{
    Console::WriteLine( "Free Function Callback " + s );
}

int main(array<System::String ^> ^args)
{
   ClassThatUsesCallback^ theClassThatUsesCallback
       = gcnew ClassThatUsesCallback();
    theClassThatUsesCallback->setCallback( FreeFunction );
    theClassThatUsesCallback->Run();
}

但是,我希望回调函数是用户代码中类的成员(因此它可以使用和更改用户代码类的属性)

以下代码无法编译

ref class ClassThatProvidesCallback
{
public:
    void MemberFunction( String^ s )
    {
        Console::WriteLine( "Member Function Callback " + s );
    }
    void Run()
    {
        ClassThatUsesCallback^ theClassThatUsesCallback
            = gcnew ClassThatUsesCallback();
        theClassThatUsesCallback->setCallback( 
            &ClassThatProvidesCallback::MemberFunction );
        theClassThatUsesCallback->Run();
    }

};

我收到此错误

error C3374: can't take address of 'ClassThatProvidesCallback::MemberFunction'
unless creating delegate instance

当我研究这个时,我发现了很多关于如何从托管代码调用未托管代码的解释(反之亦然)我不需要这样做 - 所有涉及的代码都是管理的。所以我希望有人能指出我这个简单的方法。

1 个答案:

答案 0 :(得分:1)

这是完整的解决方案:

ref class ClassThatUsesCallback
{
public:
    void setCallback( Action<String^>^ callback )
    {
        myCallback = callback;
    }
    void Run()
    {
        if( myCallback != nullptr ) {
            myCallback("This is a test");
        }
    }
private:
    Action<String^>^ myCallback;
};

ref class ClassThatProvidesCallback
{
public:
    void MemberFunction( String^ s )
    {
        Console::WriteLine( "Member Function Callback " + s );
    }
    void Run()
    {
        ClassThatUsesCallback^ theClassThatUsesCallback
            = gcnew ClassThatUsesCallback();
        theClassThatUsesCallback->setCallback(gcnew Action<String^>(this,
            &ClassThatProvidesCallback::MemberFunction));
        theClassThatUsesCallback->Run();
    }

};

int main(array<System::String ^> ^args)
{
    ClassThatProvidesCallback^ c = gcnew ClassThatProvidesCallback();
    c->Run();

    return 0;
}

本机C ++样式typedef已替换为.NET Action委托。附加参数this被添加到setCallback调用中,需要定义包含回调函数的类实例。