You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:23:41