Domanda

Sto cercando di riflettere, quindi ho deciso di aggiungere funzionalità di plugin a un programma che sto scrivendo.L'unico modo per comprendere un concetto è sporcarsi le dita e scrivere il codice, quindi ho intrapreso il percorso di creazione di una semplice libreria di interfacce composta dalle interfacce IPlugin e IHost, una libreria di implementazione di plugin di classi che implementano IPlugin e un semplice progetto console che crea un'istanza della classe di implementazione IHost che esegue un lavoro semplice con gli oggetti plug-in.

Utilizzando la riflessione, volevo scorrere i tipi contenuti nella dll di implementazione del plugin e creare istanze di tipi.Sono stato in grado di istanziare correttamente le classi con questo codice, ma non sono riuscito a trasmettere l'oggetto creato all'interfaccia.

Ho provato questo codice ma non sono riuscito a eseguire il cast dell'oggetto come mi aspettavo.Ho seguito il processo con il debugger ed è stato chiamato il costruttore corretto.L'oggetto Quickwatch o mi ha mostrato che aveva i campi e le proprietà che mi aspettavo di vedere nella classe di implementazione.

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;

Ho fatto funzionare il codice con questo.

using System.Runtime.Remoting;
ObjectHandle oh = Activator.CreateInstance(assembly.FullName, type.FullName);
// This worked as I intended
IPlugin i = (IPlugin) oh.Unwrap();
i.DoStuff();

Ecco le mie domande:

  1. Activator.CreateInstance(Type t) restituisce un oggetto, ma non sono riuscito a trasmettere l'oggetto a un'interfaccia implementata dall'oggetto.Perché?
  2. Avrei dovuto utilizzare un diverso sovraccarico di CreateInstance()?
  3. Quali sono i suggerimenti e i trucchi relativi alla riflessione?
  4. C'è qualche parte cruciale della riflessione che non riesco a capire?
È stato utile?

Soluzione

Sto solo indovinando perché dal tuo codice non è ovvio dove hai la definizione dell'interfaccia IPlugin ma se non riesci a eseguire il cast nella tua applicazione host probabilmente hai l'interfaccia IPlugin nell'assembly host e poi allo stesso tempo in l'assembly del tuo plugin.Questo non funzionerà.

La cosa più semplice per farlo funzionare è avere l'interfaccia IPlugin contrassegnata come pubblica nell'assembly host e quindi avere l'assembly del plugin assembly dell'applicazione host di riferimento, quindi entrambi gli assembly hanno accesso a la stessa interfaccia.

Altri suggerimenti

hmmm...Se stai utilizzando Assembly.LoadFrom per caricare l'assembly, prova invece a modificarlo Assembly.LoadFile.

Ha funzionato per me

Da qui: http://www.eggheadcafe.com/community/aspnet/2/10036776/solution-found.aspx

@lubos hasko

L'hai inchiodato al naso.Il mio progetto originale aveva tre diversi gruppi con l'implementazione dell'host e del plugin che facevano riferimento al gruppo dell'interfaccia del plugin.

Ho provato una soluzione separata con un'implementazione host e un assembly di interfaccia e un assembly di implementazione del plug-in.All'interno di questa soluzione, il codice nel primo blocco ha funzionato come previsto.

Mi hai dato qualcosa in più su cui riflettere, perché non capisco bene perché due assembly che fanno riferimento a un assembly comune non ottengono lo stesso tipo dall'assembly comune.

Stavo solo cercando di risolverlo da solo e sono riuscito a imbattermi nella risposta!

Avevo 3 diversi progetti C#

  • A - Progetto di interfaccia plugin
  • B - Progetto host exe -> riferimenti A
  • C - Progetto di implementazione del plugin -> riferimenti A

Ricevevo anche l'errore di casting finché non ho cambiato il nome dell'assembly per il mio progetto Plugin Interface in modo che corrispondesse allo spazio dei nomi di ciò a cui stavo cercando di eseguire il cast.

Per esempio.

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

non funzionava perché l'assembly in cui era definita l'interfaccia IPluginModule era chiamato "Common", tuttavia il tipo a cui stavo trasmettendo era "Blah.Plugins.Common.IPluginModule".

Ho cambiato il nome dell'assembly per il progetto di interfaccia in "Blah.Plugins.Common", il che significa che il cast ha avuto successo.

Speriamo che questa spiegazione aiuti qualcuno.Torniamo al codice..

Il tuo tipo non è pubblico, in tal caso chiama l'overload che accetta un valore booleano:

Activator.CreateInstance(type, true);

Inoltre, nel tuo primo esempio, controlla se o è null e, in caso contrario, stampa o.GetType().Name per vedere di cosa si tratta realmente.

@Hackerato

Ho cercato di mantenere lo pseudocodice semplice.ciascuno occupa molto spazio e bretelle.L'ho chiarito.

o.GetType().FullName restituisce Plugins.Multiply che è l'oggetto previsto.Plugins.Multiply implementa IPlugin.Ho seguito il processo nel debugger diverse volte finché non ho rinunciato per la sera.Non riuscivo a capire perché non potevo lanciarlo perché ho guardato il costruttore sparare fino a quando non sono diventato scontroso per tutto il pasticcio.Ci sono tornato stasera e l'ho fatto funzionare, ma ancora non capisco perché il cast abbia fallito nel primo blocco di codice.Il secondo blocco di codice funziona, ma mi sembra strano.

Il collegamento a Egghead sopra è la soluzione principale al problema: utilizza Assembly.LoadFile() invece di .LoadFrom()

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top