2009-10-20 3 views
19

Ho una classe (TabControlH60) che eredita da una classe base (UserControl) e implementa un'interfaccia (IFrameworkClient). Istanziato l'oggetto utilizzando la classe .NET Activator. Con l'istanza restituita, posso eseguire il cast sulla classe base UserControl, ma non sull'interfaccia. L'eccezione che ottengo è sotto il codice snipet. Come faccio a trasmettere all'interfaccia?.NET: impossibile eseguire il cast dell'oggetto per interfacciare implementa

object obj = Activator.CreateInstance(objType); 
Type[] interfaces = obj.GetType().GetInterfaces(); // contains IFrameworkClient 

m_Client = (UserControl)obj;     // base class cast works 
IFrameworkClient fc = (IFrameworkClient)obj; // interface cast fails 

// Note: The (IFrameworkClient)obj cast works fine in the debugger Watch window. 
{"Unable to cast object of type 'FPG.H60.AFF.TabControlH60' to type 
    'FPG.AFF.Interfaces.IFrameworkClient'."} 

risposta

0

Utilizzare l'operatore as :)

... 
m_Client = obj as IFrameworkClient; 
if (m_Client != null) //Remember to check for null in case the cast fails 
    ... 
... 
+0

Dopo aver riletto la tua domanda, non penso che questo fosse ciò che volevi. Scusa :) – cwap

+1

L'operatore "as" è esattamente ciò che * non si desidera * utilizzare durante il debug degli errori di cast (in silenzio inghiotte le eccezioni, non lasciando un modo semplice per eseguire il debug perché il cast non è riuscito) – ckarras

0

Il cast non funziona perché si sta cercando di gettare dal tipo object all'interfaccia. Se si sostituisce la linea di getto di interfaccia con:

IFrameworkClient fc = (IFrameworkClient)m_Client;

Funzionerà.

In alternativa, sono moderatamente sicuro che è possibile eseguire il cast dall'oggetto all'interfaccia con l'operatore as.

Vedi questo articolo per ulteriori informazioni: http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx

più un pezzo del puzzle. Interfacce non derivano da object: http://blogs.msdn.com/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx

+0

'm_Client' e' obj 'sono quasi certamente lo stesso oggetto (a meno che non sia definita una conversione). Non mi aspetto che questo abbia importanza ... –

+0

Non è così. Il mio test funziona. – Will

10

La causa più probabile è che IFrameworkClient da montaggio diverso nei due casi, ed è quindi un diverso tipo NET. Anche se è lo stesso codice, può essere di un tipo diverso.

Controllare il AssemblyQualifiedName. Si noti inoltre che se si sta caricando questo assieme con il riflesso è possibile ottenere un diverso tipo anche con lo stesso NomeQualetto Assembly, grazie al contesto di caricamento.

+1

Anche questo è stato il mio primo pensiero. –

+0

Questa è una possibilità, sicuramente. Riferimento errato. Ma qualcosa del genere di solito funziona quando si esegue il debug e non funziona quando viene distribuito (assemblaggio diverso al momento dell'implementazione). Ogni volta che mi è successo, Activator.CreateInstance non carica in modo proattivo tutti gli assembly associati a un tipo che istanzia. – Will

+0

Nel mio caso, lo stesso assembly è stato distribuito in 2 diverse directory. Il tipo è stato caricato in modo dinamico in un unico punto e convertito nell'interfaccia dall'assieme. –

0

Se la classe FPG.H60.AFF.TabControlH60 implementa effettivamente IFrameworkClient, non ci dovrebbero essere motivi per non riuscire. L'unica cosa che posso pensare a questa eccezione è se l'assembly che contiene IFrameworkClient è fortemente denominato e l'oggetto Tab Control capita di fare riferimento a una versione diversa dell'assembly contenente o si sta utilizzando un'interfaccia differente con il nome IFrameworkClient.

3

Qualcosa mi dice che il codice di esempio sta lasciando un po 'di roba ...

class Program 
{ 
    static void Main(string[] args) 
    { 
     var type = typeof(MyClass); 
     object obj = Activator.CreateInstance(type); 
     Type[] interfaces = obj.GetType().GetInterfaces(); 

     var m_Client = (UserControl)obj;   
     IFrameworkClient fc = (IFrameworkClient)obj; 
    } 
} 

public interface IFrameworkClient { } 

public class UserControl { } 

public class MyClass : UserControl, IFrameworkClient { } 

Questo compilato ed eseguito.

Scommetto che la DLL contenente la definizione di IFrameworkClient non è stata ancora caricata prima di provare a trasmettere. Questo può accadere quando usi Activator.CreateInstance.

Prova a inserire var forceLoad = typeof(IFrameworkClient); prima del cast.

3

Definire IFrameworkClient interfaccia in namespace indipendente (deve essere avere namespace) di progetto indipendente (libreria di classi) .poi aggiungere refrence della libreria di classi per il controllo del progetto e progetto principale

+0

Esattamente quello che ho fatto e funziona. – broadband

28

ho cappello gli stessi problemi con un biblioteca mia che fornisce "plugin" -funzionalità ... L'ho finalmente funzionato ...

Ecco il mio problema: ho avuto un assembly principale utilizzando plugins, un assembly con il plugin (Plugin.dll) E (importante) un altro assembly che fornisce la funzionalità plugin (Library.dll).

Plugin.dll fa riferimento all'assembly principale (per poterlo estendere) e al file Library.dll con plugin-func. - i file binari sono in una directory "./Plugins" relativa all'assembly principale.

L'assembly principale faceva riferimento anche al plugin-func. viene assemblato per utilizzare il "PluginManager". Questo "PluginManager" ottiene un percorso e carica tutti i file * .dll tramite la riflessione per analizzare se esiste un'interfaccia "IPlugin" (anch'essa proveniente da Library.dll).

Ogni volta che ho chiamato PluginManager per caricare i plug-in, non è stato possibile eseguire il cast in "IPlugin" sebbene l'abbiano implementato.

Mi sono quasi arrabbiato, ma poi ho scoperto l'intero problema. Compilando il plugin non c'era solo il "Plugin.dll" ma il "Library.dll" scritto nella directory "./Plugins". Caricando accidentalmente "Library.dll" ogni volta con il mio PluginManager, ora disponevo di due tipi di "IPlugin": uno nell'attuale "Library.dll" che viene utilizzato dall'assembly principale e uno che è stato caricato tramite il mio PluginManager - e quelli erano incompatibili!

Attenzione: se non si carica "./Plugins/Library.dll" si incontra comunque il problema, perché se si carica "Plugin.dll" che fa riferimento a "Library.dll", viene utilizzato solo quello in la stessa directory ... TILT ... !! Il mio PluginManager ora cancella semplicemente "Library.dll" dove lo trova.

L'indizio è: assicurarsi di non accedere a due assiemi in contesti diversi!

+2

Lei, signore, ha appena fatto il mio problema, che mi ha infastidito per 4 ore ormai, semplicemente vado via. Molte grazie! – beastofman

+0

Questa risposta ha bisogno di più upvotes! è stato bloccato per ore ... – MattJ

+0

Risposta molto utile, mi ha risparmiato un sacco di tempo con il problema simile. Grazie! –

1

Quando il Interface è in un assembly diverso E ho la mia classe dinamicamente a run-time in un assembly diverso, interface casting saranno falliti come il vostro campione (C# conosce la nostra interfaccia come un tipo diverso rispetto a quale classe ereditato da quello).

Questa è la mia tecnica semplice e utile in questi casi:

Quando sono sicuro che il mio Class ha ereditato dal citato Interface, quindi scrivo linea una magia (eq IFrameworkClient.) codice come questo:

dynamic fc = obj as IFrameworkClient ?? (dynamic) obj; 

Con questa tecnica è possibile:

  • scrivere i tuoi codici dopo questa riga di codice per fc a design time base su Interface members informazioni e vs sistema di editor di intelligenze.
  • prevenire ogni errore interfaccia di colata a run-time

Note:

  • È necessario C# v4 usare dynamic tipo
  • Di solito non mi piace usare dynamic tipi nei miei codici, ma può aiutarci in alcuni casi come questo
0

Nel mio caso ho dovuto aggiungere un evento build per copiare la DLL necessaria poiché stavo creando istanze e assegnando i tipi di interfaccia in fase di esecuzione. In caso contrario, la DLL caricata potrebbe non essere la DLL più aggiornata e pertanto potrebbe non eseguire il cast dell'interfaccia.

Il motivo per cui ho utilizzato gli eventi di build in questo caso (invece di aggiungere la DLL come riferimento) è che l'architettura è tale che l'applicazione principale deve fare riferimento solo ai tipi di interfaccia e tutto il resto deve essere caricato dinamicamente.

TLDR; Nel caso di tipi di caricamento dinamici da un'altra DLL, assicurati di copiare la versione più recente di quella DLL nella directory bin usando gli eventi di compilazione, altrimenti il ​​cast potrebbe non funzionare quando sembra che dovrebbe.