Frage zu Asynchronen Aufruf eines Delegates **gelöst**



  • Versuch es mal so:

    void AsyncHandler(IAsyncResult ^result)
        {
          System::Runtime::Remoting::Messaging::AsyncResult ^AsyncResult;
          AsyncResult = (System::Runtime::Remoting::Messaging::AsyncResult ^)result;
    
    	  Console::WriteLine("Bin im CTestClass asynchronen Ende-Handler");
    
          /*if (TestAADelegate = AsyncResult->AsyncDelegate)
          {
            ((TestAA  ^)AsyncResult->AsyncDelegate)->EndInvoke(result);
          }*/
    	  //IAsyncResult ^res;
    	  this->TestAADelegate->EndInvoke(result);
        }
    


  • wenn du oben die vorherigen Posts gelesen hättest wüßtest du das es das geht.

    Ich möchte es aber vereinfachen und deshalb hab ich im netz dieses VB beispiel gesehen und wollte dieses auf C++ übertragen, da das normalerweise ebenfalls geht.



  • Funktionierts jetzt oder nicht?



  • also mit der Anweisung

    TestAADelegate->BeginInvoke(5,4,3,gcnew AsyncCallback(&TestNamespace::TestAADelegate::EndInvoke),nullptr);
    

    kommt nur noch die Fehlermeldung:

    error C3352: "void TestNamespace::TestAADelegate::EndInvoke(System::IAsyncResult ^)": Die angegebene Funktion stimmt nicht mit dem Delegattyp "void (System::IAsyncResult ^)" überein.

    obwohl beides ja die selben Typen sind.



  • Ist ja auch klar, weil der Prototy für AsyncCallback folgendermaßen aussieht:

    [SerializableAttribute] 
    [ComVisibleAttribute(true)] 
    public delegate void AsyncCallback (
    	IAsyncResult^ ar
    )
    

    EndInvoke passt da leider nicht.

    Ich poste dir mal mein eigens Beispiel, da funktionierts:

    #include "stdafx.h"
    
    using namespace System;
    using namespace System::Threading;
    
    public delegate void TestAA(unsigned char Test11, unsigned char Test12,unsigned char Test13); 
    
    void Program_TestAAEvent(unsigned char Test11, unsigned char Test12, unsigned char Test13)
    {
    	Console::WriteLine("Bin im globalen asynchronen Handler vor Sleep");
    	Thread::Sleep(1000);
    	Console::WriteLine("Bin im asynchronen Handler nach Sleep");
    } 
    
    public ref class CTestClass
    {
    private:
    	AsyncCallback ^OnAsyncHandler;
    
    	static void AsyncHandlerCallback(IAsyncResult ^result)
    	{
    		Console::WriteLine("Bin im asynchronen Callback");
    		((CTestClass^)result->AsyncState)->AsyncHandler(result);
    	} 
    
    	void AsyncHandler(IAsyncResult ^result)
        {
          System::Runtime::Remoting::Messaging::AsyncResult ^AsyncResult;
          AsyncResult = (System::Runtime::Remoting::Messaging::AsyncResult ^)result;
    
    	  Console::WriteLine("Bin im CTestClass asynchronen Ende-Handler");
    
    	  this->TestAADelegate->EndInvoke(result);
        }
    
    public:
    	TestAA ^TestAADelegate; 
    
    	CTestClass()
    	{
    		TestAADelegate += gcnew TestAA(Program_TestAAEvent);
    		OnAsyncHandler = gcnew AsyncCallback(CTestClass::AsyncHandlerCallback);	
    	}
    
    	void StartAsync(int a, int b, int c)
    	{
    		IAsyncResult ^res = TestAADelegate->BeginInvoke(a, b, c, OnAsyncHandler, this); 
    	}
    };
    
    int main(array<System::String ^> ^args)
    {
        Console::WriteLine(L"Asynchrone Events");
    
    	CTestClass ^testClass = gcnew CTestClass();
    	testClass->StartAsync(1, 2, 3);
    
    	Thread::Sleep(5000);
    
        return 0;
    }
    


  • also dein Beispiel hatte ich schon am Freitag gepostet:

    using namespace System; 
    
    namespace TestNamspace 
    { 
      public delegate void TestAA(unsigned char Test11, unsigned char Test12,unsigned char Test13); 
    
      public void Program_TestAAEvent(unsigned char Test11, unsigned char Test12,unsigned char Test13){} 
    
      public ref class CTestClass 
      { 
        private: 
            AsyncCallback ^OnAsyncHandler; 
            static void AsyncHandlerCallback(IAsyncResult ^result) 
            { 
              ((CTestClass^)result->AsyncState)->AsyncHandler(result); 
            } 
    
            void AsyncHandler(IAsyncResult ^result) 
            { 
              System::Runtime::Remoting::Messaging::AsyncResult ^AsyncResult; 
              AsyncResult = (System::Runtime::Remoting::Messaging::AsyncResult ^)result; 
    
              if (TestAADelegate == AsyncResult->AsyncDelegate) 
              { 
                ((TestAA  ^)AsyncResult->AsyncDelegate)->EndInvoke(result); 
              } 
            } 
        public: 
          TestAA ^TestAADelegate; 
    
          CTestClass() 
          { 
            TestAADelegate += gcnew TestAA(Program_TestAAEvent); 
    
            OnAsyncHandler = gcnew AsyncCallback(&TestNamspace::CTestClass::AsyncHandlerCallback); 
    
            TestAADelegate->BeginInvoke(5,4,3,AsyncCallback ^OnAsyncHandler,this); 
          } 
      } 
    }
    

    EndInvoke passt nicht wegen des Rückgabetypes? Warum passt es dann in VB?



  • Ich glaube wir reden aneinander vorbei.

    Ich weiß nicht, warum es in VB funktioniert und in C++/CLI nicht. Tatsache ist, dass es so nicht funktioniert, wie Du es gepostet hat. Aber es funktioniert, wie ich es gepostet habe.

    Erklär mir bitte mal, was der Grund ist, dass Du unbedingt das VB Beispiel zum Laufen bringen willst. Dann verstehe ich dich vielleicht.



  • mein beispiel Code funktioniert auch. Ich möchte ihn nur etwas abändern.

    wenn ich sagen wir 100 Delegates habe muß ich mir ja in meinem Asynchronen Handler ein 100faches if .. else if .. und so weiter bauen damit ich weiß von welchem delegate der aufruf kam damit ich das EndInvoke rufen kann.

    Da ist es doch einfacher beim Aufruf des Delegates schon als Asynchonen Handler das EndInvoke mitzugeben damit man sich nicht mehr drum kümmern muß.



  • Hast Du 100 hundert verschiedene Delegaten in verchiedenen Objekten oder hast Du 100 Aufrufe in einem Delegat?

    Wenn Du das Delegat hast, brauchst Du EndInvoke nicht mitzuliefern, weil Du EndInvoke aufrufen kannst (siehe mein Beispiel).

    Was hält dich davon ab, deine Zeilen

    if (TestAADelegate = AsyncResult->AsyncDelegate)
              {
                ((TestAA  ^)AsyncResult->AsyncDelegate)->EndInvoke(result);
              }
    

    mit meinen

    Type ^type1 = this->TestAADelegate->GetType();
    	  Type ^type2 = AsyncResult->AsyncDelegate->GetType();
    	  if (type1 == type2)
    	  {
    		this->TestAADelegate->EndInvoke(result);
    	  }
    

    zu ersetzen?

    Ob es wiederum Sinn macht, musst Du wissen.

    P.S.: Vorsicht in C++: Bei Vergleich immer == und nicht =



  • also bei dem == hast du recht war ein Fehler ist mir beim Abschreiben des Codes passiert.

    Ich habe 100 verschieden Delegatetypen, klar kann ich ein ganz langes if .. else if ... else if usw. an der stelle machen.

    Ich finde aber die VB Version schöner deshalb habe ich nochmal gefragt aber wenn es so nicht geht:

    TestAADelegate->BeginInvoke(5,4,3,gcnew AsyncCallback(&TestNamespace::TestAADelegate::EndInvoke),nullptr);
    

    muß ich ja die if else if Variante nehmen.



  • die VB Variante sieht so aus:

    Public Shared Sub RunAsync(ByVal Action As Action)
            Action.BeginInvoke(New AsyncCallback(AddressOf Action.EndInvoke), _
                Nothing)
        End Sub
    

    dafür muß es doch eine C++ entsprechung geben.



  • Sags doch gleich:

    AsyncCallback ^aSyncCB = gcnew AsyncCallback(this->TestAADelegate, &TestAA::EndInvoke);
    IAsyncResult ^res = TestAADelegate->BeginInvoke(a, b, c, aSyncCB, nullptr);
    


  • Danke.

    Also gibt es bei dem AsyncCallback einen Konstructor mit 2 Variablen. Wäre gut gewesen wenn man sowas in der MSDN finden würde.



  • Es gibt bei jedem Delegat (und AsyncCallback ist ein Delegat) 2 Konstruktoren, weil man statische und globale Funktionen von nichtstatischen Methoden unterscheiden muss. In C# gibt es glaube ich keine globalen Funktionen mehr und in VB wird es ähnlich sein. Dann braucht man auch keine Unterscheidung.

    [url]
    http://msdn.microsoft.com/de-de/library/system.delegate.delegate(VS.80).aspx
    [/url]

    Aber ob Du EndInvoke als Async-Callback übergibst, das dann am Abschluß des asnchronen Events aufgerufen wird oder ob Du einen eigenen AsyncCallBack definierst, in dem EndInvoke aufgerufen wird, ist letzendlich egal.



  • nicht ganz.

    Denn wenn ich in dem AsyncHandler ein if für 100 Delegates bauen muß ist das erstens zeimlich viel aufwand und wenn man mal eine Funktion hinzufügt, darf man nicht vergessen dieses Delegate in den Handler reinzuschreiben.



  • Das habe ich eigentlich die ganze Zeit versucht zu erklären:

    public ref class CTestClass
    {
    private:
    	AsyncCallback ^OnAsyncHandler;
    
    	void AsyncHandlerCallback(IAsyncResult ^result)
    	{
    		Console::WriteLine("Bin im asynchronen Callback");
    		this->TestAADelegate->EndInvoke(result);
    	} 
    
    public:
    	TestAA ^TestAADelegate; 
    
    	CTestClass()
    	{
    		TestAADelegate += gcnew TestAA(Program_TestAAEvent);
    		OnAsyncHandler = gcnew AsyncCallback(this, &CTestClass::AsyncHandlerCallback);	
    	}
    
    	void StartAsync(int a, int b, int c)
    	{
    		IAsyncResult ^res = TestAADelegate->BeginInvoke(a, b, c, OnAsyncHandler, this); 
    	}
    };
    

    Das eigentlich Problem war, dass Du nicht wußtest, wie man nichtstatische Handler erzeugt. Bei einem statischen Handler (Callback) kann ich natürlich nicht auf Membervariablen zugreifen.



  • nein das war nicht das Problem, denn ich kann ja über den this Pointer in einen nichtstatischen Member meiner Klasse kommen.

    Aber deine Variante ist natürlich einefacher, den Handler nichtstatisch machen und this zeiger mit übergeben (Das es die schon gibt find ich gut).

    Aber ich wollte ja überhaupt keinen Handler und trotzdem EndInvoke aufrufen.



  • nein das war nicht das Problem, denn ich kann ja über den this Pointer in einen nichtstatischen Member meiner Klasse kommen.
    

    In einer statischen Funktion existiert kein this-Zeiger.



  • dein Beispiel mit statischer funktion:

    using namespace System; 
    
    namespace TestNamspace 
    { 
      public delegate void TestAA(unsigned char Test11, unsigned char Test12,unsigned char Test13); 
    
      public void Program_TestAAEvent(unsigned char Test11, unsigned char Test12,unsigned char Test13){} 
    
      public ref class CTestClass 
      { 
        private: 
            AsyncCallback ^OnAsyncHandler; 
            static void AsyncHandlerCallback(IAsyncResult ^result) 
            { 
              ((CTestClass^)result->AsyncState)->AsyncHandler(result); 
            } 
    
            void AsyncHandler(IAsyncResult ^result) 
            { 
              System::Runtime::Remoting::Messaging::AsyncResult ^AsyncResult; 
              AsyncResult = (System::Runtime::Remoting::Messaging::AsyncResult ^)result; 
    
              if (TestAADelegate == AsyncResult->AsyncDelegate) 
              { 
                ((TestAA  ^)AsyncResult->AsyncDelegate)->EndInvoke(result); 
              } 
            } 
        public: 
          TestAA ^TestAADelegate; 
    
          CTestClass() 
          { 
            TestAADelegate += gcnew TestAA(Program_TestAAEvent); 
    
            OnAsyncHandler = gcnew AsyncCallback(&TestNamspace::CTestClass::AsyncHandlerCallback); 
    
            TestAADelegate->BeginInvoke(5,4,3,AsyncCallback ^OnAsyncHandler,this); 
          } 
      } 
    }
    

    habe ich schon auf seite 4 mal gepostet



  • Und für was brauchst Du das if in
    void AsyncHandler(IAsyncResult ^result) ?


Anmelden zum Antworten