2012-10-25 63 views
10

我在Visual Studio 2012將參數傳遞給C++/CLI中的任務?

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

這將執行與在參數bool,任務(一類MyClass的公共非靜態成員)SwitchLaser方法對C#此代碼。

我想在託管的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#像一些解決方案,而不是創建輔助函數和成員(這不是線程安全的)。

回答

10

還沒有任何方法可以做到這一點。

在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表達式,但尚未進行管理的)。

+0

感謝您的回答。很明顯,在託管代碼中不支持lambda。儘管如此,我還是想避免創建輔助類。我在文檔中找到的是用於託管C++的Action類。這應該是能夠採用一個參數的函數,但我無法使用它,特別是與Task :: Run方法(或以某種方式與Task類一起使用它)。有沒有輔助類或輔助方法的解決方案? – Bezousek

+0

@Bezousek:'Task :: Run'需要一個'Action'委託。不,「動作」不是同一類型。閉包是用一個輔助類實現的。這就是C#編譯器在您的問題中從您的示例代碼中創建的內容,並且這是C++/CLI編譯器將在某一天添加​​託管lambda功能時將執行的操作。 –

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

用法

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

我有一個類似的問題時,我想提供執行沒有返回值的方法參數的任務(retuns void)。因爲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中使用不支持lambda表達式。