2011-11-04 12 views
7

Uso il codice seguente:Come posso ottenere un tipo da un assieme caricato da un'altra cartella?

Assembly.LoadFile("the assembly in another folder"); 
var type = Type.GetType("the full name of the type"); 

Anche se il montaggio è stato già caricato prima questa riga di codice, esso restituisce sempre null a type.

PS: ho fatto passare il nome completo dell'assembly, incluso lo spazio dei nomi, il nome del tipo, il nome dell'assembly, la versione e il token pubblico.

+0

Questo "assembly" è in qualche modo correlato al linguaggio assembly? –

+0

@KirilKirov: No. È un tipo in .Net. –

+0

@Austin - ah, grazie :) Sono stato fuorviato dal tag. –

risposta

9

Type.GetType cerca solo i tipi nell'assieme di chiamata e i tipi in mscorlib.dll a meno che non si passi il nome qualificato dell'assembly del tipo. See here.

EDIT

sembra che Type.GetType è in grado di recuperare Type istanze da assemblee nel contesto Caricare solo. Gli assembly caricati utilizzando LoadFile sono in no context e quelli caricati utilizzando LoadFrom si trovano nel contesto Load From; nessuno di questi contesti ti consente di utilizzare Type.GetType in modo che la risoluzione non riesca. This article mostra che le informazioni Type possono essere recuperate per un Assembly quando la directory in cui si trova viene aggiunta come privatePath di rilevamento poiché finirà nel contesto Load ma fallirà in altri contesti.

+0

Ho passato il nome completo dell'assembly, incluso lo spazio dei nomi, il nome del tipo, il nome dell'assembly e la versione, token pubblico. – CuiPengFei

+0

@CuiPengFei Giusto per eliminare l'ovvio, si è certi che il nome completo dell'assembly corrisponda esattamente al valore case-sensitive che si otterrebbe se si fa riferimento staticamente all'assembly e chiamato 'typeof (TypeName) .AssemblyQualifiedName'? –

+0

sì, sono sicuro. – CuiPengFei

1

si può provare questo ....

Assembly.GetAssembly presuppone che un'istanza del tipo e Type.GetType presuppone che il nome di tipo completo che include nome di assembly.

si può dare percorso che il montaggio si trova .....

Se avete solo il nome del tipo di base, è necessario fare qualcosa di più simile a questo:

public static String GetAssemblyNameContainingType(String typeName) 
{ 
    foreach (Assembly currentassembly in AppDomain.CurrentDomain.GetAssemblies()) 
    { 
     Type t = currentassembly.GetType(typeName, false, true); 
     if (t != null) {return currentassembly.FullName;} 
    } 

    return "not found"; 
} 

Ciò presuppone anche la vostra il tipo è dichiarato nella radice. Dovresti fornire lo spazio dei nomi o includere i tipi nel nome, o iterare nello stesso modo.

+0

Fare attenzione quando si caricano gli assiemi perché una volta caricati in un AppDomain non è più possibile scaricarli. Se hai molti assembly da caricare, pensa a creare AppDomain separato che eseguirà il lavoro degli assembly di elaborazione e restituirà i risultati, dopodiché potrà essere rilasciato. –

+0

Non lo raccomanderei. Invece, associare l'evento [AppDomain.AssemblyResolve] (http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyload.aspx). In questo modo, si restituisce solo l'assembly richiesto, dove nel codice sopra si cerca _each e ogni assembly caricato, più si inizia a caricare quelli non attualmente necessari_. – Abel

2

Il modo più semplice di farlo è semplicemente intercettare il valore di ritorno di Assembly.LoadFile in una variabile e chiamare GetType su di esso in questo modo:

Assembly assem = Assembly.LoadFile("assemblyLocation"); 
assem.GetType("typeName"); 

Si può prendere in considerazione mantenere un riferimento a questa assemblea se si desidera estrarre spesso i tipi da esso o fare ciò che altri hanno suggerito e creare un metodo più generico che scorre attraverso tutti gli assembly caricati.

4

Il modo "corretto" (MS consigliato) per eseguire questa operazione, quando è necessario utilizzare Type.GetType(string) sui tipi negli assiemi che non si trovano nel contesto di caricamento ma nel contesto di caricamento o di assenza di contesto, è quello di eseguire il binding al Evento Appdomain.AssemblyResolve. Il seguente codice è relativamente efficiente:

// this resolver works as long as the assembly is already loaded 
// with LoadFile/LoadFrom or Load(string)/Load(byte[]) 
private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) 
{ 
    var asm = (from a in AppDomain.CurrentDomain.GetAssemblies() 
       where a.GetName().FullName == args.Name 
       select a).FirstOrDefault(); 

    if(asm == null) 
     throw FileNotFoundException(args.Name);  // this becomes inner exc 

    return asm; 
} 

// place this somewhere in the beginning of your app: 
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve; 

Risulta leggermente più efficiente per creare una combinazione di eventi AssemblyLoad/determinazione a mantenere il dizionario dei gruppi caricati (utilizzare l'assembly nome-chiave).

In assemblaggio.LoadFile
Ci sono alcuni seri inconvenienti nell'utilizzo di questo metodo. According to MSDN:

LoadFile non carica i file nel contesto LoadFrom, e non risolve le dipendenze che utilizzano il percorso di carico, come il metodo LoadFrom fa.

Quindi, se possibile, non utilizzare LoadFile. L'assembly risultante viene caricato nel contesto no-context, che ha ancora più svantaggi rispetto al contesto load-from. Utilizzare invece Assembly.LoadFrom e le dipendenze verranno automaticamente caricate dal percorso di caricamento.

Problemi correlati