2008-08-28 8 views
10

Ich versuche, meinen Kopf um Reflexion zu wickeln, 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. Also habe ich eine einfache Interface-Bibliothek erstellt, bestehend aus den Interfaces IPlugin und IHost, einer Plugin-Implementierungsbibliothek mit Klassen, die IPlugin implementieren Konsolenprojekt, das die IHost-Implementierungsklasse instanziiert, die einfache Arbeit mit den Plugin-Objekten leistet.Wie man Objekte, die durch Reflektion erzeugt wurden, richtig ausgießt

Mit Reflektion wollte ich die Typen in meiner Plugin-Implementierungs-DLL durchlaufen und Instanzen von Typen erstellen. Ich konnte Klassen mit diesem Code erfolgreich instanziieren, aber ich konnte das erstellte Objekt nicht an die Schnittstelle übergeben.

Ich habe diesen Code versucht, aber ich konnte Objekt nicht wie erwartet o werfen. Ich bin mit dem Debugger durch den Prozess gegangen und der richtige Konstruktor wurde aufgerufen. Das Quickwatching-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 machte den Code damit arbeiten.

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 (Typ t) gibt ein Objekt, aber ich konnte das Objekt an einer Schnittstelle, die das Objekt implementiert nicht gegossen. Warum?
  2. Sollte ich eine andere Überladung von CreateInstance() verwendet haben?
  3. Was sind die Tipps und Tricks zur Reflektion?
  4. Gibt es einen entscheidenden Teil der Reflexion, die ich gerade nicht bekomme?

Antwort

4

Ich rate nur hier, weil von Ihrem Code ist es nicht offensichtlich, wo haben Sie die Definition von IPlugin Schnittstelle, aber wenn Sie nicht in Ihre Host-Anwendung zu werfen, dann haben Sie wahrscheinlich IPlugin Schnittstelle in Ihrer Host-Baugruppe und dann bei gleichzeitig in Ihrer Plugin-Assembly. Dies wird nicht funktionieren.

Die einfachste Sache ist diese Arbeit zu machen, ist IPlugin Schnittstelle als öffentlich in Ihrer Host-Baugruppe markiert hat und dann Plugin Montag Montag Referenz Host-Anwendung hat, so dass beiden Baugruppen Zugang zu haben die gleiche Schnittstelle.

+2

Vielleicht ein wenig übertrieben für eine einfache Anwendung, aber eine Alternative ist es, eine separate Bibliothek zu erstellen, die nur die Schnittstelle enthält und sie von allem, was sie darüber wissen müssen, zu beziehen: o) – Andrew

+0

Ja, Sie haben Recht. das ist auch eine gültige Lösung. –

0

Ist Ihr Typ nicht öffentlich, wenn ja, um die Überlastung aufrufen, die in einem boolean nimmt:

Activator.CreateInstance(type, true); 

Auch in Ihrem ersten Beispiel sehen, wenn o null ist und nicht, wenn, ausdrucken o .GetType(). Name, um zu sehen, was es wirklich ist.

0

@Haacked

Ich versuchte, den Pseudo-Code einfach zu halten. foreach nimmt viel Platz und Zahnspange ein. Ich habe es geklärt.

o.GetType(). FullName gibt Plugins.Multiply zurück, das das erwartete Objekt ist. Plugins.Multiply implementiert IPlugin. Ich bin ein paar Mal durch den Prozess im Debugger gegangen, bis ich den Abend aufgegeben habe. Kann nicht herausfinden, warum ich werfen konnte es nicht, weil ich das Konstruktor Feuer sah, bis ich mürrisch über die ganze Schlamassel. Kam an diesem Abend zurück, um es und machte es funktionieren, aber ich verstehe immer noch nicht, warum die Besetzung in dem ersten Codeblock ist fehlgeschlagen. Der zweite Codeblock funktioniert, aber es fühlt sich für mich an.

1

@lubos hasko

Sie nagelte ihn auf die Nase. Mein ursprüngliches Design hatte drei verschiedene Assemblys, wobei sowohl die Host- als auch die Plugin-Implementierung auf die Plugin-Schnittstellen-Assembly Bezug nahmen.

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

Sie haben mir ein bisschen mehr zum Nachdenken gegeben, weil ich nicht ganz verstehe, warum zwei Assemblies, die auf eine gemeinsame Assembly verweisen, nicht denselben Typ aus der allgemeinen Assembly erhalten.

1

Ich habe gerade versucht, dies selbst auszuarbeiten und schaffte es, auf die Antwort zu stolpern!

hatte ich 3 verschiedene C# -Projekten

  • A - Plugin Interface Projekt
  • B - Moderator exe-Projekt -> verweist auf ein
  • C - Plugin Projekt Implementierung -> verweist auf ein

Ich habe auch den Casting-Fehler bekommen, bis ich den Assemblynamen für mein Plugin Interface proj so geändert habe, dass er dem Namespace von dem entspricht, wozu ich mich beworben habe.

z.

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

versagte, weil die Anordnung, die die IPluginModule Schnittstelle wurde ‚Gemeinsame‘ genannt definiert wurde, die -Typ- ich war Gießen war ‚Blah.Plugins.Common.IPluginModule‘ jedoch.

Ich änderte den Namen der Assembly für die Schnittstelle proj zu "Blah.Plugins.Common" bedeutete, dass die Besetzung dann erfolgreich war.

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

0

Der Link oben auf Eierkopf ist die wichtigste Lösung für das Problem Verwendung Assembly.LoadFile() anstelle von .LoadFrom()

Verwandte Themen