C# Assembly zur Laufzeit einbinden und Methode aufrufen...

djfresh69

Cadet 1st Year
Registriert
Okt. 2010
Beiträge
9
Hi an alle,

möchte eine selbstgeschriebene DLL Datei zur Laufzeit einbinden und eine Methode aufrufen in der eine Funktion abgearbeitet wird.

Wie mach ich das, wenn ich ohne Verweis bzw. using arbeite ?

DLLImport geht auch nicht weil ich eben zur Laufzeit einbinde.

Bin schonmal soweit gekommen:

Code:
Assembly _oFoo = Assembly.LoadFrom(@"C:\Egal.dll");
//Namespace und Klasse instanzieren
Type _tDll = _oFoo.GetType("NameSpace.Klasse");
object _oOO = Activator.CreateInstance(_tDll);
MethodInfo _miFoo = _tDll.GetMethod("Bar");

bei _miFoo wird als Wert "null" angezeigt, obwohl Syntax etc. korrekt...

gruss

FresH
 
GetMethod sucht standardmäßig nur nach öffentlichen (public) Methoden. Außerdem wird Groß- und Kleinschreibung beachtet.
Wenn "GetMethod" also "null" liefert ist entweder der Name falsch geschrieben oder die Methode ist nicht "public".
 
@toeffi: Das kann zum Beispiel notwendig sein wenn du die DLL zur Kompilierzeit noch nicht hast, da diese als eine Art Plugin vom Kunden selbst erstellt wird und von ihm erstellte Funktionalitäten zur Verfügung stellt.

@djfresh69: Sowohl die Klasse als auch die Methode sollten public sein. Desweiteren sollte die Methode bei deiner jetzigen Vorgehensweise eine Instanzmethode sein, d.h. nicht als static definiert werden. Desweiteren sollte die Klasse einen parameterlosen public Konstruktor haben, da sonst der Activator evtl. das Objekt nicht erzeugen kann. Alles in allem sind das viele Randbedingungen die bei der Anwendung von Reflektion zutreffen müssen.

Alternative: Um dem Reflektionsteil zum Finden der Methode aus dem Weg zu gehen, könntest du auch eine Basisklasse in deiner Applikation definieren, die die abstrakte Methode enthält. Die Pluginklassen müssten dann als Konvention immer aus dieser Basisklasse erben. Danach gehts analog zu dem was du bereits hast, d.h. mit Reflektion die Assembly zur Laufzeit laden, den Typ/Klasse mit GetType abrufen. Mit dem Aktivator eine Instanz des Objektes erstellen. Dann das Objekt in Basisklasse casten und die abstrakte Methode direkt aufrufen. Das spart dir das Herausfinden der Methode über Reflektion und du hast dann im weiteren Verlauf auch kein Invoke mit den entsprechenden mehr oder weniger komplizierten Parametern zu machen, sondern wendest die Methode einfach, wie in der Basisklasse definiert, an.

Beispiel:

Deine Anwendung:

Code:
public abstract class MyBase
{
   public abstract void Hello(string sName);
}


class DoDynamicStuff
{
   void CallHello()
   {
      Assembly myAssembly = Assembly.LoadFrom(@"C:\Egal.dll");
      //Namespace und Klasse instanzieren
      Type typePlugin = myAssembly.GetType("NameSpace.Klasse");
      object objPlugin = Activator.CreateInstance(typePlugin);
      // zu Basisklasse casten
      MyBase basePlugin = objPlugin as MyBase;
      // Methode aufrufen
      objPlugin.Hello("Hans");
   }
}


die Plugin DLL:

Code:
public class Plugin : MyBase
{
   public override void Hello(string sName)
   {
       Console.WriteLine("Hello "+sName);
   }
}

Edit: Oder du nimmst alternativ zur Basisklasse ein Interface, das von den Plugins implementiert werden muss. Der Code für den Aufruf bleibt dann gleich, wie bei der Verwendung einer Basisklasse nur das eben in das Interface gecastet wird. Die Basisklasse hätte gegenüber dem Interface den Vorteil das du noch eigenen Code einbauen kannst.

Edit2: Ich habe das obige Beispiel schnell mal runter getippt, prüfen ob es geht, musst du.
 
Zuletzt bearbeitet:
@toeffi: Es ist eine selbstgeschriebene DLL in C#

@TheCadillacMan: Klasse und die Methode sind public, hab mit reflection schon über get/set, sowie methoden mit return und methoden die ich als virtual in der DLL deklariert habe erfolgreich werte ausgelesen, nun habe ich noch eine weitere klasse zur DLL hinzugefügt und möchte gewisse funktionen ausführen, aber ich komm bis jetzt nicht drauf wie ich die methode aus meiner "Basis Applikation" zum laufen bringe...

@Rossibaer: du hast es genau erkannt vielen dank, es sollen in zukunft weitere DLLs folgen, mit der gemeinsamkeit des NameSpaces z.B. damit die Hauptapplikation nicht ständig neu kompiliert werden muss.

Also die Klasse und die Methode sind public;
Methode ist nicht static;
parameteroser public konstruktor ist in folgender form vorhanden:
public Klasse() {}
das abstrakt hilft mir ja die methode zu überschreiben,
wenn ich keinen parameter übergeben muss kann ich es ja auch
public void ... lassen oder?

also ich glaub ich hab den fehler gefunden:

bei Invoke hab ich entweder das falsche objekt aufgerufen oder es war irgendwo anders ein Fehler den ich grad nicht nachvollziehen kann:
Code:
object _oLogin = _miInfo.Invoke(_oOO, null);

dein Codebeispiel sah interessant aus aber es kam ein fehler bezüglich System.Type und Unboxing/Boxing [...] ...trotzdem danke für den Hinweis...

Nun noch eine kleine weitere Frage:

Die Dll endet in einer Endlosschleife.
Ist es möglich die Methode der Dll mit einem Delegaten aufzurufen ?
damit die Hauptapplikation weiter läuft und quasi weitere Funktionen abgearbeitet werden und wenn die fertig sind die Dll "beendet" (dispose) wird ?
 
Zuletzt bearbeitet:
@Rossibaer: jaja,wann das nötig ist, wusst ich ja selber, ich dachte nur der TE weiß es vielleicht nicht und lädt die Dll unnötiger weiße erst zur laufzeit. Aber das ist ja nicht der fall, also ist es so ok:D
 
Zurück
Oben