传递一个参数在C ++到任务/ CLI?(Pass an argument to task in C

2019-08-01 22:09发布

我在的Visual Studio 2012的代码为C#。

public Task SwitchLaserAsync(bool on)
{
   return Task.Run(new Action(() => SwitchLaser(on)));
}

这将执行SwitchLaser方法(一类的公共非静态成员MyClass ),作为与变量bool任务。

我想这样做在托管C ++ / CLI类似的东西。 但我无法找到任何方式如何运行任务,将执行成员方法取一个参数。

目前的解决办法是这样的:

Task^ MyClass::SwitchLaserAsync( bool on )
{
    laserOn = on;   //member bool 
    return Task::Run(gcnew Action(this, &MyClass::SwitchLaserHelper));
}

实施SwitchLaserHelper功能:

void MyClass::SwitchLaserHelper()
{
     SwitchLaser(laserOn);
}

必须有像C#,而不是创建辅助功能和成员的一些解决方案(这不是线程安全的)。

Answer 1:

目前还没有任何办法做到这一点。

在C#中你有一个闭合。 当你的C ++ / CLI编译器是书面的,仍然正在讨论在C ++倒闭标准化的语法。 值得庆幸的是,微软选择了等待,并使用标准的lambda语法,而不是引入又一独特的语法。 不幸的是,这意味着该功能尚未公布。 当是时,它看起来是这样的:

gcnew Action([on](){ SwitchLaserHelper(on) });

当前线程的解决办法是做什么的C#编译器 - 把辅助函数和数据成员没有到当前的类,但到嵌套子类型。 当然,你需要保存this指针,除了局部变量。

ref class MyClass::SwitchLaserHelper
{
    bool laserOn;
    MyClass^ owner;

public:
    SwitchLaserHelper(MyClass^ realThis, bool on) : owner(realThis), laserOn(on) {}
    void DoIt() { owner->SwitchLaser(laserOn); }
};

Task^ MyClass::SwitchLaserAsync( bool on )
{
    return Task::Run(gcnew Action(gcnew SwitchLaserHelper(this, on), &MyClass::SwitchLaserHelper::DoIt));
}

C ++的语法lamdba将只需创建辅助类你(目前适用于本地lambda表达式,但尚未进行管理的)。



Answer 2:

这里的通用代码,我写今天下午这可能帮助(虽然它不是为这个问题完全匹配)。 也许这将帮助旁边的人谁绊倒了这个问题。

generic<typename T, typename TResult>
ref class Bind1
{
    initonly T arg;
    Func<T, TResult>^ const f;
    TResult _() { return f(arg); }

public:
    initonly Func<TResult>^ binder;
    Bind1(Func<T, TResult>^ f, T arg) : f(f), arg(arg) {
        binder = gcnew Func<TResult>(this, &Bind1::_);
    }
};

ref class Binder abstract sealed // static
{
public:
    generic<typename T, typename TResult>
    static Func<TResult>^ Create(Func<T, TResult>^ f, T arg) {
        return (gcnew Bind1<T, TResult>(f, arg))->binder;
    }
};

用法

const auto f = gcnew Func<T, TResult>(this, &MyClass::MyMethod);
return Task::Run(Binder::Create(f, arg));


Answer 3:

我有一个类似的问题时,我想提供执行不返回值(retuns的方法的参数的任务void )。 正因为如此Func<T, TResult>不是一种选择我可以使用。 欲了解更多信息,请点击页面使用返回void类型的新Func键 。

所以,我结束了一个解决方案,我创建了一个辅助类

template <typename T>
ref class ActionArguments
{
public:
    ActionArguments(Action<T>^ func, T args) : m_func(func), m_args(args) {};
    void operator()() { m_func(m_args); };

private:
    Action<T>^ m_func;
    T m_args;
};

其使用Action<T>委托来封装具有单个参数,并且不返回值的方法。

然后我会用这个辅助类的方式如下

ref class DisplayActivationController
{
public:
    DisplayActivationController();

    void StatusChanged(EventArgs^ args) { };
}


Action<EventArgs^>^ action =
    gcnew Action<EventArgs^>(this, &DisplayActivationController::StatusChanged);
ActionArguments<EventArgs^>^ action_args =
    gcnew ActionArguments<EventArgs^>(action, args);
Threading::Tasks::Task::Factory->
    StartNew(gcnew Action(action_args, &ActionArguments<EventArgs^>::operator()));

使用辅助类的做法可能不是最好的解决方法,但是是最好的我能找到在C ++ / CLI中使用不支持lambda表达式。



Answer 4:

这里的工作答案..已测试它..传递参数(INT)的行动sampleFunction。

#include "stdafx.h"
#include "CLRSamples.h"

using namespace System;
using namespace System::Threading;
using namespace System::Threading::Tasks;
using namespace System::Collections;
using namespace System::Collections::Generic;

void CLRSamples::sampleFunction(Object^ number)
{
    Console::WriteLine(number->ToString());
    Thread::Sleep((int)number * 100);
}

void CLRSamples::testTasks()
{
    List<Task^>^ tasks = gcnew List<Task^>();

    for (int i = 0; i < 10; i++)
    {
        tasks->Add(Task::Factory->StartNew((Action<Object^>^)(gcnew Action<Object^>(this, &CLRSamples::sampleFunction)), i));
    }

    Task::WaitAll(tasks->ToArray());

    Console::WriteLine("Completed...");
}

int main(array<System::String ^> ^args)
{
    CLRSamples^ samples = gcnew CLRSamples();
    samples->testTasks();

    Console::Read();
    return 0;
}


文章来源: Pass an argument to task in C++/CLI?