Kommunikation zwischen Assemblys



  • Hallo,

    es liegt folgende Situation vor:
    In einer Applikation werden mehrere Assemblys zur Laufzeit dynamisch über die Reflection geladen, sagen wir Assembly A1, A2 und A3. Assembly A1 besitzt Funktionen F1 und F2. A2 hat die Funktionen F3 und F4.
    Nun ist es ja auch mit Hilfe des Reflection-Namespace möglich Methoden einer geladenen Assembly über die Main-Form aufzurufen.
    Mein Problem liegt nun aber darin, wie die Assembly A3 die Funktionen F1 von A1 und F3 von A2 aufrufen kann, also Methodenaufrufe der Assemblys untereinander.

    Habe mir schon mal Interfaces angeschaut, bin mir aber nicht sicher ob ein Interface in diesem Fall angebracht ist, denn die Assemblys sollen völlig unabhängig voneinander existieren können.

    Überlegung:
    Die Assemblies besitzen alle ihre eigene Form,die beim Programmstart angezeigt werden. Für jede Form wird das von Activator::CreateInstance zurückgelieferte Objekt in einer Klasse gespeichert.Wenn es nun möglich wäre, dass die Assemblys Zugriff auf diese Klasse mit den Objekten hätten, könnten sie über das Objekt einer anderen Assembly auch eine entsprechende Methode aufrufen oder?

    Code zum Laden der Assembly:

    Assembly^ a = Assembly::LoadFrom(DLLPath);
    Type^ type = a->GetType("OptZange.Zange");   
    if (a->GetType("OptZange.Zange") != nullptr)
      {
        //Instanzen ist eine Klasse zur Verwaltung der Assembly-Instanzen s.u.
        ob = Instanzen->getInstance(2,type,this);
        OptZange_Form = safe_cast<Form^>(ob);
        OptZange_Form->MdiParent=this;
        OptZange_Form->Show();    
      }
    

    Die aufgerufene Methode Instanzen->getInstance(..) sieht wie folgt aus:

    [/cSystem::Object^ TGetInstance::getInstance(System::Int16 ModulNr,System::Type^ type,System::Object^ arg)
    {
    	switch(ModulNr)
    	{
    		case 1: if (BV_INSTANZ==nullptr)
    	  			{
    					BV_INSTANZ = System::Activator::CreateInstance(type,arg);
    					return(BV_INSTANZ);
    				}
    			    else
    		    	{
    			 		return(BV_INSTANZ);
    			    }	
    
    		case 2: if (ROBOTER_INSTANZ==nullptr)
    				{
    					ROBOTER_INSTANZ = System::Activator::CreateInstance(type,arg);
    					return(ROBOTER_INSTANZ);
    				}
    				else
    				{
    					return(ROBOTER_INSTANZ);
    				}
    
    		case 3: if (SCRIPTER_INSTANZ==nullptr)
    				{
    					SCRIPTER_INSTANZ = System::Activator::CreateInstance(type,arg);
    					return(SCRIPTER_INSTANZ);
    				}
    		   		else
    			    {
    					return(SCRIPTER_INSTANZ);
    				}
    	}
    }
    

    Ich bedanke mich schon mal im Voraus für Eure Ratschläge, viele Grüße
    Cain



  • Ich würde eine Assembly "BasicData" machen, welche von allen dreien benutzt wird. Darin sind "nur" die Interfaces enthalten und eine "Verwaltung" der aktuell registrieren "Dienste" (Klassen).
    Jede Assembly (A1, A2, A3, ...) hat nun immer einen Verweis auf diese Basis-Assembly. Darin gibt es z.B. einen statische Methode "GetService", wobei dann das gewünschet Interface übergeben wird (oder man kann es auch via Strings (Namen) machen). Diese sucht dann bei den schon "aktivierten" Assemblies nach diesem Serice-Namen (oder Interface) und gibt die Referenz darauf zurück. So kann jetzt jede Assembly mit dem passenden "Service" kommunizieren, der ja in einer beliebigen anderen Assembly sein kann.

    Wird eine Assembly geladen, so muss sich diese natürlich bei dem Basis-Assembly "anmelden".

    Alternativ kann man natürlich eine Konfigurationsdatei machen, wo die "Services" beschrieben sind und dann, nach Anfrage, automatisch die passende Assembly geladen wird, falls diese noch nicht registriert ist. Dies wäre zumindest der von mir bevorzugte Weg. So hat man alle Services/Assemblies/Instanzen in z.B. einer XML-Datei definiert.



  • Erst einmal vielen Dank für Deinen Rat Jochen, habe dazu noch ein paar konkrete Fragen, da ich noch nicht so vertraut bin dem Umgang von Assemblys und Interfaces.

    Darin sind "nur" die Interfaces enthalten

    -> Funktionen, die innerhalb eines Interfaces deklariert sind, müssen ja in jeder Assembly, die dieses Interface verwendet, implementiert werden. Da die Funktionalität der Assemblys aber unabhängig voneinander sein soll, kann/muss man dann mehrere Interfaces in der BasicData-Assembly definieren, und je nach Assembly dann das entsprechende Interface verwenden?

    eine "Verwaltung" der aktuell registrieren "Dienste" (Klassen)

    ->Könnte das so eine Klasse sein, wie ich sie oben beschrieben habe, wo die Instanzen der Assemblys verwaltet werden?

    Darin gibt es z.B. einen statische Methode "GetService", wobei dann das gewünschet Interface übergeben wird (oder man kann es auch via Strings (Namen) machen). Diese sucht dann bei den schon "aktivierten" Assemblies nach diesem Serice-Namen (oder Interface) und gibt die Referenz darauf zurück. So kann jetzt jede Assembly mit dem passenden "Service" kommunizieren, der ja in einer beliebigen anderen Assembly sein kann.

    -> Da habe ich noch etwas Probleme mit der Umsetzung, wie übergebe ich ein beliebiges Interface an eine Assembly A1, und wenn es ein Interface einer anderen Assembly A2 ist, braucht A1 keine Implementierung der Funktionen aus A2?

    Vielen Dank und viele Grüße
    Cain



  • DeckCain schrieb:

    Da die Funktionalität der Assemblys aber unabhängig voneinander sein soll, kann/muss man dann mehrere Interfaces in der BasicData-Assembly definieren, und je nach Assembly dann das entsprechende Interface verwenden?

    Ja. Du kannst auch in einer Klasse mehrere Interfaces implementieren. Der andere muss davon ja nichts wissen, sondern kann einfach zur Laufzeit abfragen ob die Instanz das Interface implementiert.

    DeckCain schrieb:

    ->Könnte das so eine Klasse sein, wie ich sie oben beschrieben habe, wo die Instanzen der Assemblys verwaltet werden?

    genau. Diese könnte der Einfachheit-halber auch in der "Basis-Assembly" drin sein. Da ja jedes "PlugIn" diese Funktionen kennen muss. Somit enthält die Basis-Assembly doch mehr als nur die reinen Interfaces...

    DeckCain schrieb:

    -> Da habe ich noch etwas Probleme mit der Umsetzung, wie übergebe ich ein beliebiges Interface an eine Assembly A1, und wenn es ein Interface einer anderen Assembly A2 ist, braucht A1 keine Implementierung der Funktionen aus A2?

    Einer Assembly kannst Du kein Interface geben. Nur einer Klasse oder einem Field zuweisen.
    Wie Du das machst ist ganz von Dir abhängig...


Anmelden zum Antworten