2009-01-21 12 views
5

Ich bin mit dem folgenden Code ein paar Probleme mit:Type.IsSubclassOf() funktioniert nicht über AppDomains?

private class ClientPluginLoader : MarshalByRefObject 
{ 
    public bool IsPluginAssembly(string filename) 
    { 
     AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler(CurrentDomainReflectionOnlyAssemblyResolve); 

     Assembly asm = Assembly.ReflectionOnlyLoadFrom(filename); 

     Type[] types = asm.GetTypes(); 
     foreach (Type type in types) 
     { 
      if (type.IsSubclassOf(typeof(ClientPlugin))) 
      { 
       return true; 
      } 
     } 

     return false; 
    } 
} 

Der Code wird über einen Proxy genannt, die ich durch meine benutzerdefinierte App Domain CreateInstanceFromAndUnwrap erstellt haben(). Dies bedeutet, dass IsPluginAssembly() im Kontext meiner benutzerdefinierten App-Domäne ausgeführt wird.

Das Problem ist, dass der Aufruf von IsSubclassOf() immer false zurückgibt, obwohl es IMHO True zurückgeben sollte. Der betreffende "Typ" erbt wirklich von ClientPlugin - daran besteht kein Zweifel.

ClientPlugin ist in einer anderen privaten Assembly definiert, die ich manuell auflöse, wie im obigen Codefragment ersichtlich ist.

type.BaseType == typeof(ClientPlugin) 

Auf der anderen Seite ist dieser Ausdruck wahr:

type.BaseType.FullName == typeof(ClientPlugin).FullName 

Wie ist das möglich

ich einen Haltepunkt auf der if (type.IsSubclassOf(...)) Linie und bestätigt diesen Ausdruck falsch sein gesetzt haben ? Was ist los?

UPDATE: Kent Boogaart wies mich in die richtige Richtung. Ich suchte das Web ein wenig mehr und lief in this Blogpost. Es scheint, dass ich meine Load/LoadFrom/ReflectionOnlyLoadFrom-Konflikte auflösen muss, damit dies funktioniert.

Antwort

7

Dies ist aufgrund des Ladens in einen anderen Kontext. Wie Sie eine Assembly laden (Load/LoadFrom/ReflectionOnlyLoad), bestimmt, in welchen Kontext sie geladen wird. Dieses einfache Beispiel zeigt auch das Problem:

using System; 
using System.Reflection; 

class Foo 
{ 
    public static void Main() 
    { 
     var type = typeof(Foo); 
     var reflectionLoadType = Assembly.ReflectionOnlyLoad("ConsoleApplication1").GetType("Foo"); 
     Console.WriteLine(type == reflectionLoadType); //false 
     Console.WriteLine(type.Equals(reflectionLoadType)); //false 

     Console.WriteLine("DONE"); 
     Console.ReadKey(); 
    } 
} 

here Siehe für weitere Informationen.

2

Ich hatte ein ähnliches Problem. Ich hatte auch diese Architektur - eine .DLL, die ClientPlugin-Basisklasse enthält; mehrere Plugins, die auf diese .DLL verweisen; und eine Hauptanwendung, die ebenfalls auf diese .DLL verweist. Das Problem bestand darin, dass die .DLL mit der ClientPlugin-Basisklasse in zwei Ordner kopiert wurde - in den Ordner "Plugins" und in den Hauptanwendungsordner. So wurde es zweimal in meine AppDomain geladen (Plugins luden es auch indirekt). Und als die Hauptanwendung versuchte, Magie vom Reflexionstyp zu tun, schlug sie fehl, weil es zwei Instanzen des Typs ClientPlugin gab.

Obwohl ich nicht denke, dass dies genau dein Fall ist, gibt es noch eine Lektion zu lernen - wenn ein .DLL zweimal geladen wird, werden die Typen auch dupliziert. In meinem Fall würde ich entweder separate AppDomains oder das "ReflectionOnlyLoad" vermuten, weil die .DLL dann irgendwie anders geladen wird.

+0

Ich hatte genau dieses Problem, ich hatte zwei Kopien der gleichen DLL in zwei Ordnern. Beim Ausführen der "IsSubclassOf" manuell, habe ich diese Fehlermeldung erhalten: Der Typ 'ServiceCore.BaseService' existiert sowohl in 'ServiceCore.dll' und 'ServiceCore.dll' – vpalmu