2008-12-05 8 views
18

Ich arbeite an einem Plugin-System, das .dll's in einem angegebenen Ordner lädt. Ich benutze dann Reflektion, um die Assemblys zu laden, iteriere durch die Typen, die sie enthalten, und identifiziere alle, die meine IPlugin Schnittstelle implementieren.IsAssignableFrom() gibt false zurück, wenn es true zurückgeben soll

ich dies mit Code bin Überprüfung ähnlich der folgenden:

foreach(Type t in myTypes) 
{ 
    if(typeof(IPlugin).IsAssignableFrom(t)) 
    { 
     ... 
    } 
} 

Aus irgendeinem Grund IsAssignableFrom() hält false zurückgibt, wenn es wahr zurückkehren sollte. Ich habe versucht, das t zu ersetzen, indem ich ihm ausdrücklich einen Typ gebe, der übergeben werden sollte, und es funktioniert gut, aber aus irgendeinem Grund arbeitet es nicht mit den Typen, die von der geladenen Assembly zurückgegeben werden. Um etwas merkwürdiger zu machen, funktioniert der Code auf der Maschine meines Kollegen, aber nicht auf meiner.

Weiß jemand etwas, das diese Art von Verhalten verursachen könnte?

Dank

Antwort

27

Das tritt normalerweise auf, wenn die Assembly, die den Typ IPlugin enthält, auf die die aktuelle Assembly verweist, und die Assembly, auf die von der Assembly verwiesen wird, die die Iterationsarten enthält, nicht übereinstimmen . über

ich schlage vor, Sie drucken:

typeof (IPlugin).Module.FullyQualifiedName 

und

foreach (var type in t.GetInterfaces()) 
{  
    Console.WriteLine (type.Module.FullyQualifiedName) 
} 

Um zu sehen, wo das Mismatch ist.

+0

In meinem Fall schlägt Typvergleich nur bei einer Schnittstelle fehl und es funktioniert gut für alle anderen Schnittstellen, die in derselben Baugruppe definiert sind! Warum sollte das passieren? Die Assembly, die die Schnittstelle enthält, wird mithilfe des Post-Build-Ereignisses des Projekts in den Ordner "bin \ debug" der Anwendung kopiert. Ich denke also, dass die Assembly, auf die in meinem Startprojekt verwiesen wird (unter Verwendung der direkten Projektreferenz), dieselbe ist wie die, die im Ordner "bin \ debug" der Anwendung kopiert wurde. Ist das nicht der Fall? – Learner

+0

Das war es für mich. Mein Modul hat die Version 2.0.0.0 der Assembly, die den Typ enthält, den ich überprüft habe, refecten, während der implementierende Typ einen Typ mit demselben Namen aus Version 2.1.0.0 dieser Assembly implementiert hat. –

+1

Es scheint mir, dass dies fehlschlägt, wenn die Assemblys in einen reinen Reflektionskontext geladen werden. Auch wenn beide Typen den gleichen * AssemblyQualifiedName * haben. –

0

ich in Java arbeiten, die die gleiche API-Methode hat, und ich kann einfach nicht mein Verstand es grok erhalten, wenn Sie den Code lesen (aus irgendeinem Grund); daher lese ich es immer in umgekehrter Reihenfolge, da in Ihrem Fall "t zu IPlugin zuweisbar ist." Wenn also C# "ist", wie Jonathon vorschlägt, würde ich es immer verwenden - wenn ich in Java "instanceof" finde, funktioniert das nicht Klassenobjekte, nur Instanzen des Objekts

-2

Der Name der Type.IsAssignableFrom-Methode ist vage und verwirrend, wenn sie zum Testen der Vererbung oder zum Erkennen von Schnittstellenimplementierungen angewendet wird. Die folgenden Wrapper für diese Zwecke würden viel mehr Sinn machen:

public static bool CanBeTreatedAsType(this Type CurrentType, Type TypeToCompareWith) 
    { 
     // Always return false if either Type is null 
     if (CurrentType == null || TypeToCompareWith == null) 
      return false; 

     // Return the result of the assignability test 
     return TypeToCompareWith.IsAssignableFrom(CurrentType); 
    } 

Dann kann man verständlichere Anwendungscode hat wie:

bool CanBeTreatedAs = typeof(SimpleChildClass).CanBeTreatedAsType(typeof(SimpleClass)); 
    CanBeTreatedAs = typeof(SimpleClass).CanBeTreatedAsType(typeof(IDisposable)); 

Der Vorteil dieser Methode anstelle der ‚ist‘ Das Schlüsselwort ist, dass es zur Laufzeit verwendet werden kann, um unbekannte, willkürliche Typen zu testen, während das Schlüsselwort 'is' (und ein generischer Typparameter) Kenntnisse über die Kompilierung bestimmter Typen benötigt.

0

Manchmal ist es ein Problem mit der dynamischen Assembly, die auf eine andere Assembly verweist.

Eine einfache Sache, um lokale Kopie auf der Baugruppe zu deaktivieren (in Visual Studio mit der rechten Maustaste auf die Referenz und legen Sie Kopie lokal auf false). Dies sollte es einfacher machen, das Verzeichnis zu lokalisieren, in dem die Baugruppe lebt.

Sie können auch einen Assembly-Resolver implementieren, der in .NET nicht wissen kann, wie der Typ initialisiert werden soll.

 AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler([Resolve Function]); 
4

Einige andere Antworten haben den Mangel an Klarheit im Namen der Methode IsAssignableFrom erwähnt. Ich stimme zu und nutzte es daher falsch.

Versuchen Sie ein wenig experimentieren mit die Objekte in Ihrem Code umkehren und sehen, ob es funktioniert. Ersetzen

: Zum Beispiel

if (typeof(IPlugin).IsAssignableFrom(t)) 

mit:

if (t.IsAssignableFrom(typeof(IPlugin))) 

Auf diese Weise nur ich nicht habe es, zu arbeiten, aber begann zu verstehen, was diese Methode tatsächlich der Fall ist.

+0

Das klingt eigentlich falsch. Laut der Dokumentation (https://msdn.microsoft.com/pl-pl/library/system.type.isassignablefrom(v=vs.110).aspx) wird true zurückgegeben, wenn * die aktuelle Instanz eine von c implementierte Schnittstelle ist *. Dies macht "i.IsAssignableFrom (t)" in diesem Szenario gültig. –

3

Ich hatte das gleiche Problem, wenn die Schnittstelle in einer separaten Assembly zu implementieren Typ definiert wurde. Das Iterieren und Laden von Assemblys aus dem Stammordner, der dlls mit Klassen und dll mit der Schnittstelle enthielt, führte zu einer Typabweichung, wie oben erwähnt.

Eine Lösung war LoadFrom()-LoadFile() Die LoadFrom Methode hat einige Nachteile zu ändern, und das ist einer von ihnen:

Wenn eine Baugruppe mit der gleichen Identität bereits geladen ist, gibt Loadfrom die geladene Assembly selbst wenn Ein anderer Pfad wurde angegeben.

Ein anderer Weg, dies zu überwinden ist es, alle DLLs mit Typen zu platzieren Schnittstelle in separate Ordner Implementierung und nicht referenzierte Assembly (CopyLocal = False) so Assembly.LoadFrom wird nicht geladen DLL enthält Schnittstelle in den Speicher zu kopieren.

+0

Ich bin in genau dieser Situation gelandet und das hat den Trick für mich gemacht. – Larry

Verwandte Themen