2012-10-25 11 views
10

Ich habe diesen Code für die C# in Visual Studio 2012.Übergeben Sie ein Argument an Aufgabe in C++/CLI?

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

Dieser auf SwitchLaser Methode (public nicht statisches Mitglied einer Klasse MyClass) als eine Aufgabe mit dem Argumente Bool ausgeführt wird.

Ich möchte etwas ähnliches in verwalteten C++/CLI tun. Aber ich bin nicht in der Lage, einen Weg zu finden, wie man eine Aufgabe ausführt, die eine Member-Methode ausführt, die einen Parameter verwendet.

Aktuelle Lösung ist wie folgt:

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

Implementierung von SwitchLaserHelper Funktion:

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

Es muss eine Lösung wie in C# und nicht Helferfunktionen und Mitglieder (dies ist nicht THREAD zu erstellen).

Antwort

10

Es gibt noch keine Möglichkeit, dies zu tun.

In C# haben Sie eine Schließung. Als Ihr C++/CLI-Compiler geschrieben wurde, wurde die standardisierte Syntax für Closures in C++ noch diskutiert. Zum Glück hat Microsoft entschieden, zu warten und die Standard-Lambda-Syntax zu verwenden, anstatt eine weitere eindeutige Syntax einzuführen. Leider bedeutet dies, dass die Funktion noch nicht verfügbar ist. Wenn es ist, wird es etwas wie folgt aussehen:

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

Die aktuelle Thread-Lösung zu tun, was Compiler die C# tut - setzen die Hilfsfunktion und Datenelemente nicht in der aktuellen Klasse, sondern in einem verschachtelten Subtyp. Natürlich müssen Sie den Zeiger this zusätzlich zu Ihrer lokalen Variablen speichern.

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

Die lamdba Syntax ++ C wird einfach diese Hilfsklasse für Sie erstellen (zur Zeit es für native lambdas funktioniert, aber noch nicht für verwaltete sind).

+0

Danke für die Antwort. Es ist klar, dass Lambda im verwalteten Code nicht unterstützt wird. Trotzdem möchte ich die Erstellung der Hilfsklassen vermeiden. Was ich in der Dokumentation gefunden habe, ist die Klasse Aktion für verwaltetes C++. Dies sollte in der Lage sein, eine Funktion mit einem Argument aufzunehmen, aber ich konnte es nicht verwenden und insbesondere nicht mit einer Task :: Run-Methode (oder irgendwie mit einer Task-Klasse verwenden). Gibt es eine Lösung ohne Hilfsklasse oder Hilfsmethoden? – Bezousek

+0

@Bezousek: 'Task :: Run 'benötigt einen' Action' Delegaten. Nein, eine 'Aktion ' ist nicht vom selben Typ. Closures werden mit einer Hilfsklasse implementiert. Dies erstellt der C# -Compiler aus Ihrem Beispielcode in Ihrer Frage, und das wird der C++/CLI-Compiler eines Tages tun, wenn gemanagte Lambda-Funktionen hinzugefügt werden. –

3

Hier ist generischer Code, den ich heute nachmittag geschrieben habe, was helfen könnte (obwohl es für diese Frage nicht genau passt). Vielleicht hilft das der nächsten Person, die auf diese Frage stößt.

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

Verbrauch ist

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

Ich hatte ein ähnliches Problem, wenn ich eine Methode ausgeführt wird, die nicht zurückgibt einen Wert (Retuns void) einen Parameter einer Aufgabe zur Verfügung zu stellen wollte. Aus diesem Grund Func<T, TResult> war keine Option, die ich verwenden könnte. Weitere Informationen finden Sie auf der Seite Using void return types with new Func.

So landete ich mit einer Lösung, wo ich eine Hilfsklasse erstellt

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

die Action<T> Delegat wird mit einer Methode kapseln, die einen einzelnen Parameter hat und gibt keinen Wert.

Ich würde dann in einer folgenden Art und Weise diese Hilfsklasse verwenden

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())); 

Ansatz unter Verwendung der Hilfsklasse ist wahrscheinlich nicht die eleganteste Lösung, aber es ist die beste, die ich in C++/CLI verwendet werden finden konnten die Lambda-Ausdrücke nicht unterstützt.