C++/CLI委托回调
我们都习惯了在c#中使用事件,但是c++中没有默认的事件机制,所以在编写c++/cli时,这将是一个令人困扰的问题
在c++中常见的方式是传入一个回调,在特定的时机,通过调用回调函数,执行上层的代码。
这种方式能够解决一部分场景的问题,但是另外一些场景,比如事件的invok列表,责任链模式都不能实现。
另外常见的回调对象,要求一次实现多个回调函数,这样容易将各个业务的处理都聚集在同一个回调对象中,不利于解耦。
在c++/cli中,一种可以参考的处理方式是使用一个托管类对非托管的回调类进行封装。向非托管的回调类传入一个托管类的委托函数后,由委托函数重新引发.NET事件。
//非托管部分Callback.h
public class Callback:Public AbstractCallback
{
private:
typedef std::function<void(void)> FooCallback;
FooCallback _fooCallback;
public:
inline void OnFoo() override
{
if (_fooCallback)
{
_fooCallback();
}
}
inline void SetFooCallback(FooCallback callback)
{
_fooCallback=callback;
}
}
//托管部分Wrapper.h
public ref class Wrapper
{
private:
Callback* _callback;
delegate void DelegateOnFoo();
DelegateOnFoo^ _onFoo;
void InitCallback();
void OnFoo(){FooEvent(this,gcnew EventArgs())}
public:
event EventHandler^ FooEvent;
}
//托管部分Wrapper.cpp
void Wrapper::InitCallback()
{
using namespace std;
_callback = new Callback();
_onFoo = gcnew DelegateOnFoo(this, &Wrapper::OnFoo);
IntPtr pvFun1 = Marshal::GetFunctionPointerForDelegate(safe_cast<Delegate^>(_onFoo));
_callback->SetFooCallback((void(*)(void))pvFun1.ToPointer());
}
其中需要注意的几点是:
我们生成了一个托管的委托,DelegateOnFoo,但是对于非托管的回调来说他只能接受对应的函数指针,因此,需要使用Marshal::GetFunctionPointerForDelegate将其转换为指针
此时我们得到的是一个IntPtr智能指针对象,我们需要使用ToPointer方法将其转换为void*,然后再强转为参数匹配的(void(*)(void))格式,才能传入非托管方法
另外,最容易忽略的一点是我们通过_onFoo字段保留了这个委托的引用。对于DelegateOnFoo来说,他是一个.NET对象,由gcnew生成,通过gc进行内存管理,如果不保留引用则随时可能被gc回收。而我们传入非托管对象的是其地址,那么一旦委托被回收,则托管部分运行就会出错。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
2017-11-12 EL表达式
2017-11-12 WEB服务器、应用程序服务器、HTTP服务器区别
2015-11-12 oracle drop table and purge
2014-11-12 Qt之XML(一) DOM