如何将Ref类成员函数传入TaskRunner::Create实现一键Task创建
实现无需手动创建Action的Task封装类
当然可以实现你想要的简洁调用方式!我们可以借助C++/CLI的泛型特性,让TaskRunner::Create直接接收对象实例、成员函数指针和参数,内部自动完成委托的创建与绑定。
完整实现代码
下面是调整后的TaskRunner类,支持直接传入对象、成员函数和参数:
ref class TaskRunner abstract sealed { public: // 单参数成员函数的Create重载 generic<typename TObj, typename TArg0> static Task^ Create(TObj^ obj, void (TObj::*func)(TArg0), TArg0 arg0) { return Task::Run(gcnew Action(gcnew BindAction<TObj, TArg0>(obj, func, arg0), &BindAction<TObj, TArg0>::Invoke)); } // 扩展:无参数成员函数的Create重载 generic<typename TObj> static Task^ Create(TObj^ obj, void (TObj::*func)()) { return Task::Run(gcnew Action(gcnew BindAction<TObj>(obj, func), &BindAction<TObj>::Invoke)); } private: // 无参数的绑定辅助类 generic<typename TObj> ref class BindAction { initonly TObj^ _obj; initonly void (TObj::*_func)(); public: BindAction(TObj^ obj, void (TObj::*func)()) : _obj(obj), _func(func) {} void Invoke() { (_obj->*_func)(); } }; // 单参数的绑定辅助类 generic<typename TObj, typename TArg0> ref class BindAction { initonly TObj^ _obj; initonly void (TObj::*_func)(TArg0); initonly TArg0 _arg0; public: BindAction(TObj^ obj, void (TObj::*func)(TArg0), TArg0 arg0) : _obj(obj), _func(func), _arg0(arg0) {} void Invoke() { (_obj->*_func)(_arg0); } }; };
简洁调用方式
现在你可以摆脱手动创建Action的繁琐,直接这样创建Task:
// 调用无参数成员函数 auto task1 = TaskRunner::Create(this, &MyClass::MyVoidMethod); // 调用单参数成员函数 auto task2 = TaskRunner::Create(this, &MyClass::MyMethodWithArg, myArgValue);
Visual Studio 2015编译器Bug说明
正如你提到的,VS2015存在一个编译器限制:无法自动推导不同参数数量的泛型委托类型。因此如果你需要支持多参数的成员函数,必须为每个参数数量单独定义对应的BindAction类和Create重载,不能复用同一个泛型类模板处理不同参数长度的场景。
比如要支持双参数的成员函数,需要额外添加以下代码:
// 双参数的Create重载 generic<typename TObj, typename TArg0, typename TArg1> static Task^ Create(TObj^ obj, void (TObj::*func)(TArg0, TArg1), TArg0 arg0, TArg1 arg1) { return Task::Run(gcnew Action(gcnew BindAction<TObj, TArg0, TArg1>(obj, func, arg0, arg1), &BindAction<TObj, TArg0, TArg1>::Invoke)); } // 双参数的绑定辅助类 generic<typename TObj, typename TArg0, typename TArg1> ref class BindAction { initonly TObj^ _obj; initonly void (TObj::*_func)(TArg0, TArg1); initonly TArg0 _arg0; initonly TArg1 _arg1; public: BindAction(TObj^ obj, void (TObj::*func)(TArg0, TArg1), TArg0 arg0, TArg1 arg1) : _obj(obj), _func(func), _arg0(arg0), _arg1(arg1) {} void Invoke() { (_obj->*_func)(_arg0, _arg1); } };
添加后就能在VS2015中正常编译运行了。
内容的提问来源于stack exchange,提问作者Hector
相关产品推荐
相关产品推荐

