将ref类成员函数作为参数传递

时间:2018-01-24 11:22:12

标签: .net c++-cli

我正在尝试创建一个包装器,允许在一个衬里中创建System :: Task对象。到目前为止,我有以下工作 -

ref class TaskRunner abstract sealed
{
public:
    generic<typename TArg0>
    static Task^ Create(Action<TArg0>^ f, TArg0 arg0) {
        return Task::Run((gcnew BindAction1<TArg0>(f, arg0))->binder);
    }
private:
    generic<typename TArg0>
    ref class BindAction1
    {
        initonly TArg0 _arg0;
        Action<TArg0>^ const f;
        void _() { return f(_arg0); }
    public:
        initonly Action^ binder;
        BindAction1(Action<TArg0>^ f, TArg0 arg0) : f(f), _arg0(arg0) {
            binder = gcnew Action(this, &BindAction1::_);
        }
    };
}

可以通过 -

调用
auto task = TaskRunner::Create(gcnew Action<TArg0>(this, &Class::Function), arg0);

但是我想删除手动创建操作的需要。即修改Create,使调用看起来像 -

auto task = TaskRunner::Create(this, &Class::Function, arg0);

并在Create中调用gcnew Action(obj,func)。我不知道这是否可行。如果是这样,我将如何声明create?

的参数

实际上,他们需要与Action代理相同。查看系统库Action似乎采用了System :: Object和System :: IntPtr,但我无法使用它们作为参数。

*更新 - 感谢IllidanS4提供完整的答案,并帮助您完成此工作。对于任何试图在他的答案中使用代码的人来说,Visual Studio 2015中似乎存在一个编译器错误,它需要为每个参数链长度覆盖delegate_type。

1 个答案:

答案 0 :(得分:2)

来自ECMA-372:

  

尝试在其他任何上下文中获取非本机类的成员函数的地址的程序   比起代表的创建,是不正确的。成员的成员没有指向成员的表示   非本地课程。

不幸的是,这意味着&Class::Function无效。在我看来,这种限制是没用的,因为CIL中的ldftn指令恰恰是在委托构造中编译的内容。 A&#34;指向托管函数的指针&#34;遗憾的是,C ++ / CLI中缺少类型,尽管它显然存在于CIL中。

所以不,必须传递一个包含在委托中的方法。但是,如果您对宏开放,则可以使用以下内容:

#define CreateTask(obj, func, arg) TaskRunner::Create(gcnew System::Action<decltype(arg)>(obj, func), arg)

编辑:让这个也适用于 Func 的情况有点棘手,但它也适用于一些模板:

template <class Ret, class... Args>
struct delegate_type
{
    using type = System::Func<Args..., Ret>;
};

template <class... Args>
struct delegate_type<void, Args...>
{
    using type = System::Action<Args...>;
};

#define CreateTask(obj, func, arg) TaskRunner::Create(gcnew delegate_type<decltype(obj->func(arg)), decltype(arg)>::type(obj, &func), arg)

请勿将其与&Class::Function一起使用,而是通过Class::Function