2010-05-24 14 views
6

Abbiamo creato un piccolo componente che accetta un ID, cerca una voce nel database per un assembly/spazio dei nomi/classe e carica dinamicamente un'istanza della classe che siamo dopo. Fino ad ora ha funzionato bene, ma quando si esegue questo codice in VS 2010, non funziona.Problema con il caricamento dinamico degli assiemi in .NET

Private Function AssemblyLoaded(ByVal assemblyFile As String) As Assembly 
    Dim assemblies() As Assembly = AppDomain.CurrentDomain.GetAssemblies 

    For Each asmb As Assembly In assemblies 
     If (asmb.Location = assemblyFile)) Then Return asmb 
    Next 
    Return Nothing 
End Function 

Il primo problema è che quando l'iteratore colpisce un montaggio dinamico, non c'è asmb.Location e un NotSupportedException viene generata. C'è un modo per verificare l'assenza di supporto del campo Posizione senza dover rilevare l'eccezione?

Il secondo problema, asmb.Location restituisce l'intero percorso anziché solo il nomefile, il che significa che questa funzione non riesce ogni volta. Se questa funzione determina che una classe non è già stata caricata, proviamo a caricarla e ottenere una AccessViolationException perché la classe è già stata caricata e non possiamo "ricaricarla".

Modifica della funzione per questo funziona:

Private Function AssemblyLoaded(ByVal assemblyFile As String) As Assembly 
    Dim assemblies() As Assembly = AppDomain.CurrentDomain.GetAssemblies 

    For Each asmb As Assembly In assemblies 
     Try 
      If (asmb.Location.EndsWith(assemblyFile)) Then Return asmb 
     Catch ex As NotSupportedException 
      Continue For 
     End Try 
    Next 

    Return Nothing 
End Function 

ma si sente sporca. C'è un modo migliore per verificare se un assembly è già stato caricato e restituirlo al chiamante? I problemi sopra specifici di .NET 4.0 o Visual Studio 2010? Non ho provato questo al di fuori dell'IDE in quanto richiede una configurazione abbastanza significativa.

risposta

5

È possibile verificare se l'assieme è dinamico saltando le istanze di AssemblyBuilder. Dovresti utilizzare Path.GetFileName() per isolare il nome. Fai attenzione che questa non è una buona idea dato che gli assiemi di percorsi diversi possono avere nomi identici. Ma tu sembri essere bloccato con questo. Così:

Private Function AssemblyLoaded(ByVal assemblyFile As String) As Assembly 
    For Each asmb As Assembly In AppDomain.CurrentDomain.GetAssemblies 
     If TypeOf asmb Is System.Reflection.Emit.AssemblyBuilder Then Continue For 
     If System.IO.Path.GetFileName(asmb.Location) = assemblyFile Then Return asmb 
    Next 
    Return Nothing 
End Function 

La sensibilità alle maiuscole è qualcosa che dovresti affrontare, forse.

+0

Questo funziona, grazie. Ho rimosso il .ToLower per brevità, ma trattiamo la distinzione tra maiuscole e minuscole. –

2

Da aggiungere alla anwer di Hans Passant: per la mia applicazione (C# 4.0), saltano le istanze di AssemblyBuilder ancora non riuscite. Risulta che esiste un'altra classe, System.Reflection.Emit.InternalAssemblyBuilder, che genera anche un quando si accede a Location.

InternalAssemblyBuilder e RuntimeAssembly (il tipo desiderato) sono sia interne, in modo che il meglio che ho potuto venire in mente è (in C#):

var assemblies = AppDomain.CurrentDomain 
    .GetAssemblies() 
    .Where(assembly => assembly.GetType().Name == "RuntimeAssembly") 
    .Select(assembly => assembly.Location) 
    .ToArray(); 
+1

Se stai usando .Net 4.0, dovresti controllare Assembly.IsDynamic, che copre tutte le basi –

+0

@DenisTroller grazie per quel commento - dovresti lasciarlo come risposta :) – Jedidja

0

Se si utilizza Net 4.0, si dovrebbe verificare Assembly.IsDynamic, che copre tutte le basi ...

Problemi correlati