2012-10-25 12 views
10

私は、これは、引数のブール上でタスクとしてSwitchLaserメソッド(クラスMyClassの公開非静的メンバー)を実行します2012年C++/CLIでタスクに引数を渡しますか?

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

のVisual StudioでC#の場合、このコードを持っています。

私はマネージC++/CLIで同様のことをしたいと思います。しかし、私はどのようにどのように1つのパラメータを取るメンバメソッドを実行するタスクを実行する方法を見つけることができません。

現在のソリューションは、このようなものです:SwitchLaserHelper機能の

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

実装:

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

ありC#でのようないくつかのソリューションでなければならず、ヘルパー関数とメンバーを作成しない(これはスレッドセーフではありません)。

答えて

10

これを行う方法はまだありません。

C#にはクロージャがあります。あなたのC++/CLIコンパイラが書かれたとき、C++のクロージャのための標準化された構文がまだ議論されていました。ありがたいことに、マイクロソフトは、もう1つのユニークな構文を導入するのではなく、標準のラムダ構文を待って使用することにしました。残念ながら、この機能はまだ利用できません。それがあるとき、それはのようなものになります。現在のスレッドセーフ・ソリューションは、C#コンパイラが何をやっている

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

を - 現在のクラスにいないヘルパー関数とデータメンバを置くが、ネストされたサブタイプに。もちろん、ローカル変数に加えてポインタを保存する必要があります。

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構文は、単純に(現在はそれがネイティブラムダのために動作しますが、まだ管理のためのもの)あなたのためのヘルパークラスを作成します。 (それはこの質問のための完全な一致はありませんが)

+0

お返事ありがとうございます。ラムダはマネージコードでサポートされていないことは明らかです。それでも私はヘルパークラスの作成を避けたいと思います。私がドキュメントで見つけたのは、マネージC++のクラスアクションです。これは1つの引数を持つ関数を取ることができるはずですが、私はそれを使用できませんでした。特にTask :: Runメソッドで(または何らかの形でそれをTaskクラスで使用して)使用できませんでした。ヘルパークラスやヘルパーメソッドのないソリューションはありますか? – Bezousek

+0

@Bezousek: 'Task :: Run'は' Action'デリゲートを必要とします。いいえ、「アクション」は同じタイプではありません。クロージャは、ヘルパークラスで実装されます。これは、あなたの質問にあなたのサンプルコードからC#コンパイラが作成するものです。管理されたラムダ機能が追加されると、C++/CLIコンパイラはいつかそれを実行します。 –

3

ここでは、一般的なコードは、私が役立つかもしれない今日の午後を書いたのです。多分、これはこの質問につまずく次の人を助けるでしょう。

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; 
    } 
}; 

使用方法は、私は(voidをretuns)値を返さないメソッドを実行するタスクにパラメータを提供したいとき、私は同様の問題があった

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

です。そのため、Func<T, TResult>は私が使用できるオプションではありませんでした。詳細については、Using void return types with new Funcページをご確認ください。

だから、私は、単一のパラメータを受け取り、戻り値を持たないメソッドをカプセル化するAction<T>デリゲートを使用している

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; 
}; 

ヘルパークラスを作成したソリューションになってしまいました。

私は、ヘルパークラスを使用して

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で使用されることを見つけることができる最高のもので、次のように、このヘルパークラスを使用します

ラムダ式をサポートしていません。

関連する問題