Action^ mit Task C++/CLI

Hallihallo,

ich hätte da mal gerne ein problem…

ich krieg das Action Object in verbindung mit Tasks nicht auf die Reihe.

(Diese Methode soll aufgerufen werden)

Void sendNewData(Remote ^remote){...}

Die Abarbeitung eine Netzwerkanfrage erfolgt hier…
(Das remote-object enthält ein verbundenes Socketobjekt über das die Daten hin und her geschickt werden sollen)

Void ReceiveData(TransferDataCommand^ cmd, 
 Remote ^remote){
 Tasks::Task ^task;
 Console::WriteLine("Eingehender Datenstrom von {0}...",remote-\>RemoteIP());
 switch (cmd-\>Command){
 case NetCommand::RequestNewData:
 Console::WriteLine("Anfrage für neues Datenpaket!");
 {
 Action^\> ^action = gcnew 
Action^\>(this, &LottoServer::sendNewData);
 try{
 task = gcnew Tasks::Task(action); //Fehler: 
 task-\>Start();
 }catch(Exception ^ex){
 Console::WriteLine("Fehler: {0}",ex-\>Message);
 }
 }
 break;
....

Der Compiler meldet :
Error 1 error C2664: ‚System::Threading::Tasks::Task::Task(System::Action ^)‘ : cannot convert parameter 1 from ‚System::Action ^‘ to ‚System::Action ^‘ …

ich habe schon versucht in der Zeile mit
task = gcnew Tasks::Task(action);
Das action objekt wie folgt zu casten
task = gcnew Tasks::Task((Action^)action);

dabei wir das Programm auf fehlerfrei überetzt, allerding wir dann das Programm mit einer invalid Cast Exception „abgebrochen“.

Auch habe ich versucht die Methoden so umzubauen, das Argumente vom Typ Object^ akzeptiert werden. Das war genauso erfolglos.

Mir erschließt sich aber auch nicht so wirklich wie ich Parameter an die newData Methode übergebe. die MSDN war dabei nicht wirklich hilfreich.

Ich wäre für jede Hilfe wirklich dankbar

Enrico

Hallo,

eine Action ist ein Delegat, der keinen Parameter nimmt. Eine Action ist ein Delegat, der einen Parameter vom Typ T nimmt. Natürlich kannst du die beiden Delegaten nicht ineinander casten.
Dir hilft hier eine Überladung des Konstruktors von Task, der sowohl den Delegaten als auch den Parameter nimmt:

task = gcnew Tasks::Task(action, remote);

Nico

vielen Dank, also krieg ich Parameter schon mal in den Task.
Ich habe nun alles so umgestellt das die Funktion paramter Object^ nimmt. das funktioniert soweit auch aber ich krieg es nicht gebacken einen Task zu erstellen, dem ich einen Wert übergebe kann und auch ein Result-Wert zurück erhalte. Zu diesem Zweck hab ich ein kleines Testprojekt erstellt.

Int32 quad(Int32 j){
 Thread::Sleep(1000);
 return j\*j;
}
int main(array ^args)
{
 Int32 value = 64;
 Action ^action = gcnew Action(&quad);
 Task ^task = gcnew Task(action, value);
 task-\>Start();
 Console::WriteLine("ich mach dann schon mal weiter!");
 Int32 j = task-\>Result;
 Console::WriteLine(j);

hier komm ich nicht klar wie das Action und das Task element genau definiert werden muss. so wie es da ist ist es falsch.
Als Fehler erhalte ich:
Error 1 error C3352: ‚quad‘ : the specified function does not match the delegate type ‚void (int)‘
Error 2 error C2664: ‚System::Threading::Tasks::Task::Task(System::Func ^,System::open_mouth:bject ^)‘ : cannot convert parameter 1 from ‚System::Action ^‘ to ‚System::Func ^‘

Enrico

1 Like

Hallo,

eine Action gibt keinen Wert zurück. Dafür brauchst du eine Func. Wir behalten das kurz im Hinterkopf und ich komme zum zweiten Problem.
Ein Task kann an sich nur ein Object als Parameter bekommen. Die aufgerufene Funktion ist dann dafür zuständig, das Object entsprechend zu casten. Also bauen wir eine Wrapper-Funktion, die das leistet.

Int32 callQuad(System::open\_mouth:bject^ j)
{
 return quad((int)j);
}

Und dazu bauen wir die gesuchte Func:

Func^ action = gcnew Func(&callQuad);
Task^ task = gcnew Task(action, value); 

Der Rest bleibt wie gehabt.

Nico

Hallo Nico,

super das Funktioniert… vielen vielen Dank!

also verwendet man Action ausschließlich für den Aufruf von Methoden, während man Funktionen mit Func aufruft?
Ist das der einzige Unterschied zwischen den Beiden Objekten?

Enrico

1 Like

Ja, das ist der einzige Unterschied.
Die Signaturen sind die folgenden:

Func =\> TR Methode(T1, T2, T3 ...)
Action =\> void Methode(T1, T2, T3 ...)

Nico

1 Like

na nun wird mir so einiges klar.

vielen Dank für diese Erkenntnis :smile:

Enrico

*grml* einen hab ich dann doch noch…

wie bekomme ich es denn hin einen Task mit 2 oder mehr Parametern zu erstellen? die Func hab ich, funktioniert auch. aber der Task macht da probleme.

Mein code bis hier hin

Int32 add(Int32 a, Int32 b){
 Random rnd;
 Thread::Sleep(rnd.Next(6000)+100);
 return a+b;
}
Int32 callAdd(Object ^a, Object ^b){
 return add((Int32)a,(Int32)b);
}

int main(array ^args)
{
 Random rnd;
 Int32 value;

 Func^ mADD = 
 gcnew Func(&callAdd);
 value = rnd.Next(1000)+1;
 //Task ^task2 = gcnew Task(mADD,value, value+1);
 //task2-\>Start();
(...)
}

Das erstellen des Tasks funktioniert nicht, da keine 3 Argumente im konstruktor akzeptiert werden. ich könnte zwar alternativ eine struktur erstellen, aber geht das nicht „sauberer“?

Enrico

Eine schöne Variante gibt es leider nicht. Du musst mit einem Object auskommen. Eventuell hilft dir hier aber ein Tuple, sodass du keine struct erstellen musst.

Nico