2012-04-05 7 views
3

Einer meiner Baugruppen enthält die folgenden ‚Anbieter‘ Typen:Casting auf Basisklasse wirft InvalidCastException

InheritanceTree

ich auch eine XML-Datei, die Anbieterdaten mit der DeviceInfoProvider Basisklasse hält. Eine vereinfachte Version sieht wie folgt aus:

<DeviceInfoProvider Type="SbRioI2CProvider" Assembly="assembly.dll" > 
</DeviceInfoProvider> 
<DeviceInfoProvider Type="GenericProvider" Assembly="assembly.dll" > 
</DeviceInfoProvider> 

Zur Laufzeit Karte I XML-Felder meiner Variablen:

assembly.dll ⇒ assemblyPath 
Type   ⇒ typeName 

und nach dem Lesen von XML, verwenden Sie den folgenden Code meine Typen zu instanziiert:

var assembly = Assembly.LoadFrom(assemblyPath); 

var type = (from t in assembly.GetTypes() 
      where t.IsPublic && t.Name == typeName 
      select t).FirstOrDefault(); 

if (type != null) 
{ 
    instance = type.GetConstructor(Type.EmptyTypes).Invoke(null); 
} 

Wie erwartet, generiert dies meine Objekte entsprechend.

Das Problem kommt, wenn ich versuche Instanz als Basisklasse Objekt zu werfen:

using (var provider = instance as DeviceInfoProvider) 
{ 
    // provider is null! 
} 

Der Laufzeittyp von instance ist die erwartete abgeleitete Klasse, aber ich bin nicht in der Lage erfolgreich es zu seinem Basistyp zu werfen.

Was fehlt mir?

+0

Was ist der Wert der Variablen 'typeName'? Lesen Sie aus dem XML- oder einem Const-String-Wert "DeviceInfoProvider"? – llj098

+0

sind alle diese Typen in der gleichen Baugruppe? –

+0

@mikez: die aus XML geladenen Typen müssen nicht alle in derselben Baugruppe sein –

Antwort

2

Ihr Problem sein kann, dass Sie Instanzen (GenericProvider, SbRioI2CProvider) von Typen in assembly.dll im Kontext Loadfrom schaffen. Dann versuchen Sie, nach einem Typ (DeviceInfoProvider) in dieser Assembly zu benennen. Dies verwendet implizit den Ladekontext. Typen aus derselben Assembly, die jedoch in verschiedenen Kontexten geladen sind, werden von der Laufzeit als unterschiedliche Typen betrachtet, sodass die Umwandlung fehlschlägt und Sie null erhalten. This Artikel bietet einige zusätzliche Erklärung der Assembly Binding Kontexte.

Damit diese Umwandlung erfolgreich ausgeführt werden kann, müssen Sie den im Load-Kontext geladenen Wert Assembly in den LoadFrom-Kontext laden. Es gibt mehrere Möglichkeiten, dies zu tun. Eine Möglichkeit besteht darin, die Baugruppe in den GAC zu stellen. Eine andere Möglichkeit besteht darin, die Assembly.dll aus der Anwendungsdatenbank zu entfernen, damit sie nicht durch Sondieren gefunden wird. Verwenden Sie dann das AppDomain.AssemblyResolve-Ereignis, um das Assembly zu laden, das Sie über LoadFrom erhielten.

+0

Danke für die Erklärung und den Link. Es war der Trick, der Versammlung einen starken Namen zu geben! –

0

Das Aufrufen des Konstruktors eines reflektierten Typs erstellt keine Instanz davon. Um eine Instanz eines reflektierten Typs zu erstellen, rufen Sie Activator.CreateInstance auf.

Es sieht aus wie diese Linie sein soll:

if (type != null) { 
    instance = Activator.CreateInstance(type) 
} 

Dies wird instance Ursache des Typ sein object, aber jetzt können Sie es werfen, was Sie wollen.

Siehe: http://msdn.microsoft.com/en-us/library/wccyzw83.aspx

+0

Also, was ist der Rückgabewert der 'Invoke' Methode? – llj098

+0

Du hast mich. http://msdn.microsoft.com/de-us/library/6ycw1y17.aspx 'Eine Instanz der Klasse, die dem Konstruktor zugeordnet ist. Ich habe noch nie zuvor eine Instanz eines reflektierten Typs gesehen. –

+0

Wenn Sie Ihren Linq-Ausdruck weiter filtern, um Typen auszusortieren, die nicht von 'DeviceInfoProvider' abgeleitet sind, erhalten Sie immer noch denselben Typ, nach dem Sie gesucht haben? –

Verwandte Themen