Frage

Ich versuche, mich mit der Reflexion auseinanderzusetzen, also habe ich beschlossen, einem Programm, das ich schreibe, Plugin-Fähigkeit hinzuzufügen.Die einzige Möglichkeit, ein Konzept zu verstehen, besteht darin, sich die Finger schmutzig zu machen und den Code zu schreiben. Deshalb habe ich den Weg gewählt, eine einfache Schnittstellenbibliothek zu erstellen, die aus den IPlugin- und IHost-Schnittstellen, einer Plugin-Implementierungsbibliothek mit Klassen, die IPlugin implementieren, und einer einfachen Konsolenprojekt, das die IHost-Implementierungsklasse instanziiert, die einfache Arbeit mit den Plugin-Objekten erledigt.

Mithilfe von Reflection wollte ich die in meiner Plugin-Implementierungs-DLL enthaltenen Typen durchlaufen und Instanzen von Typen erstellen.Mit diesem Code konnte ich Klassen erfolgreich instanziieren, aber ich konnte das erstellte Objekt nicht in die Schnittstelle umwandeln.

Ich habe diesen Code ausprobiert, aber ich konnte das Objekt nicht wie erwartet umwandeln.Ich habe den Prozess mit dem Debugger durchlaufen und der richtige Konstruktor wurde aufgerufen.Das schnelle Beobachten von Objekt o zeigte mir, dass es die Felder und Eigenschaften hatte, die ich in der Implementierungsklasse erwartet hatte.

loop through assemblies
  loop through types in assembly
    // Filter out unwanted types
    if (!type.IsClass || type.IsNotPublic || type.IsAbstract )
      continue;
    // This successfully created the right object
    object o = Activator.CreateInstance(type);
    // This threw an Invalid Cast Exception or returned null for an "as" cast
    // even though the object implemented IPlugin      
    IPlugin i = (IPlugin) o;

Ich habe dafür gesorgt, dass der Code damit funktioniert.

using System.Runtime.Remoting;
ObjectHandle oh = Activator.CreateInstance(assembly.FullName, type.FullName);
// This worked as I intended
IPlugin i = (IPlugin) oh.Unwrap();
i.DoStuff();

Hier sind meine Fragen:

  1. Activator.CreateInstance(Type t) gibt ein Objekt zurück, aber ich konnte das Objekt nicht in eine Schnittstelle umwandeln, die das Objekt implementiert hat.Warum?
  2. Hätte ich eine andere Überladung von CreateInstance() verwenden sollen?
  3. Welche Tipps und Tricks gibt es zum Thema Reflexion?
  4. Gibt es einen entscheidenden Teil der Reflexion, den ich einfach nicht verstehe?
War es hilfreich?

Lösung

Ich vermute hier nur, weil aus Ihrem Code nicht ersichtlich ist, wo Sie die Definition der IPlugin-Schnittstelle haben, aber wenn Sie Ihre Hostanwendung nicht umwandeln können, dann haben Sie wahrscheinlich eine IPlugin-Schnittstelle in Ihrer Host-Assembly und dann gleichzeitig in Ihre Plugin-Assembly.Das wird nicht funktionieren.

Der einfachste Weg, dies zum Laufen zu bringen, besteht darin, die IPlugin-Schnittstelle in Ihrer Host-Assembly als öffentlich zu markieren und dann Ihre Plugin-Assembly einzurichten Referenz-Hostanwendungsassembly, sodass beide Baugruppen Zugriff darauf haben die gleiche Schnittstelle.

Andere Tipps

Hmmm...Wenn Sie Assembly.LoadFrom zum Laden Ihrer Assembly verwenden, versuchen Sie stattdessen, Assembly.LoadFile zu ändern.

Hat bei mir funktioniert

Von hier: http://www.eggheadcafe.com/community/aspnet/2/10036776/solution-found.aspx

@lubos hasko

Du hast es auf den Punkt gebracht.Mein ursprünglicher Entwurf hatte drei verschiedene Assemblys, wobei sowohl die Host- als auch die Plugin-Implementierung auf die Plugin-Schnittstellen-Assembly verwiesen.

Ich habe eine separate Lösung mit einer Host-Implementierungs- und Schnittstellen-Assembly und einer Plugin-Implementierungs-Assembly ausprobiert.Innerhalb dieser Lösung funktionierte der Code im ersten Block wie erwartet.

Sie haben mir etwas mehr zum Nachdenken gegeben, weil ich nicht ganz verstehe, warum zwei Assemblys, die auf eine gemeinsame Assembly verweisen, nicht denselben Typ aus der gemeinsamen Assembly erhalten.

Ich habe gerade versucht, das selbst herauszufinden und bin über die Antwort gestolpert!

Ich hatte 3 verschiedene C#-Projekte

  • A – Plugin-Schnittstellenprojekt
  • B – Host-Exe-Projekt -> Verweise auf A
  • C – Plugin-Implementierungsprojekt -> Referenzen A

Ich habe auch den Umwandlungsfehler erhalten, bis ich den Assemblynamen für mein Plugin-Schnittstellenprojekt so geändert habe, dass er mit dem Namespace dessen übereinstimmt, in den ich umwandeln wollte.

Z.B.

IPluginModule pluginModule = (IPluginModule)Activator.CreateInstance(curType);

schlug fehl, weil die Assembly, in der die IPluginModule-Schnittstelle definiert wurde, „Common“ hieß. Der Typ, in den ich umgewandelt habe, war jedoch „Blah.Plugins.Common.IPluginModule“.

Ich habe den Assembly-Namen für das Schnittstellenprojekt in „Blah.Plugins.Common“ geändert, was bedeutete, dass die Umwandlung dann erfolgreich war.

Hoffentlich hilft diese Erklärung jemandem.Zurück zum Code..

Ist Ihr Typ nicht öffentlich, rufen Sie in diesem Fall die Überladung auf, die einen booleschen Wert aufnimmt:

Activator.CreateInstance(type, true);

Überprüfen Sie in Ihrem ersten Beispiel außerdem, ob o null ist. Wenn nicht, drucken Sie o.GetType().Name aus, um zu sehen, was es wirklich ist.

@Gehackt

Ich habe versucht, den Pseudocode einfach zu halten.foreach nimmt viel Platz und Klammern ein.Ich habe es geklärt.

o.GetType().FullName gibt Plugins.Multiply zurück, das das erwartete Objekt ist.Plugins.Multiply implementiert IPlugin.Ich habe den Prozess im Debugger einige Male durchlaufen, bis ich für den Abend aufgegeben habe.Ich konnte nicht herausfinden, warum ich es nicht wirken konnte, denn ich sah zu, wie der Konstruktor feuerte, bis ich über das ganze Durcheinander mürrisch wurde.Ich bin heute Abend darauf zurückgekommen und habe es zum Laufen gebracht, aber ich verstehe immer noch nicht, warum die Umwandlung im ersten Codeblock fehlgeschlagen ist.Der zweite Codeblock funktioniert, aber für mich fühlt es sich komisch an.

Der Link zu egghead oben ist die Hauptlösung für das Problem. Verwenden Sie Assembly.LoadFile() anstelle von .LoadFrom().

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top