我正在尝试创建一个包装器,允许在一个衬里中创建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。
答案 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
。