我知道这个错误消息有很多答案,但我未能找到解决我的问题的方法。我正在玩从非托管 C++ 通过 C++/CLI 到 C# 的函数调用。棘手的部分是我想将 C 回调函数指针向下传递到函数参数列表中的 C# 代码,然后从 C# 代码中调用此回调。它“原则上”是有效的,但有一个问题让我感到困惑。 (使用 Visual Studio 2022 17.6.5)
这个 C# 类被编译成程序集:
namespace CsWorker
{
public class CsWorkerClass
{
public delegate int Callback();
public int DoSomething(int i, Callback cb)
{
return i+cb();
}
}
}
我围绕程序集创建了一个 C++/CLI 包装类,该类被编译成单独的 DLL:
(头文件WrapperClass.h)
class WorkerClass;
class __declspec(dllexport) WrapperClass
{
public:
using tCallback = int (*)(void);
WrapperClass();
~WrapperClass();
int DoSomething(int i, tCallback cb);
private:
WorkerClass* m_pWorker{};
};
(实现文件WrapperClass.cpp)
#include "WrapperClass.h"
#include <msclr/auto_gcroot.h>
#include <msclr/marshal_cppstd.h>
using namespace System::Runtime::InteropServices;
using namespace CsWorker;
class WorkerClass
{
public:
static int MyCallback()
{
return 77;
}
int DoSomething(int i, int(*cb)(void))
{
// The static_assert is not triggered
static_assert(std::is_same_v<decltype(cb), decltype(&MyCallback)>);
// The following line compiles
/*return*/ m_pWorker->DoSomething(i, gcnew CsWorker::CsWorkerClass::Callback(&MyCallback));
// This line doesn't compile
// error C3352: 'int (__cdecl *__cdecl cb)(void)': the specified function does not match the delegate type 'int (void)'
return m_pWorker->DoSomething(i, gcnew CsWorker::CsWorkerClass::Callback(cb));
}
msclr::auto_gcroot<CsWorkerClass^> m_pWorker{};
};
WrapperClass::WrapperClass()
{
m_pWorker = new WorkerClass;
m_pWorker->m_pWorker = gcnew CsWorkerClass;
}
WrapperClass::~WrapperClass()
{
delete m_pWorker;
}
int WrapperClass::DoSomething(int i, tCallback cb)
{
return m_pWorker->DoSomething(i, cb);
}
当两个参数的类型相同时,为什么通过
&MyCallback
编译的行和通过 cb
的行会产生错误?将 int(void)
函数转换为 int(void)
委托有什么问题?
一位同事向我推荐了 CodeProject 上的文章 C++/CLI:在委托中存储 Lambda,它为我的问题提供了解决方案。说实话,我并不声称理解它,但它确实有效!