2010-05-24 24 views
6

Hemos creado un pequeño componente que toma una identificación, busca una entrada en la base de datos para un ensamblado/espacio de nombres/clase y carga dinámicamente una instancia de la clase que estamos después. Ha funcionado bien hasta ahora, pero cuando se ejecuta este código en VS 2010, está fallando.Problema con la carga dinámica de ensamblados en .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 

El primer problema es que cuando el repetidor realiza un ensamblado dinámico, no hay asmb.Location, y una NotSupportedException es lanzada. ¿Hay alguna manera de verificar el campo No admitido del Lugar sin tener que atrapar la excepción?

El segundo problema, asmb.Location es devolver la ruta completa en lugar de solo el nombre de archivo, lo que significa que esta función falla cada vez. Si esta función determina que una clase no está cargada, trataremos de cargarla y obtendremos una AccessViolationException porque la clase ya se ha cargado y no podemos "volver a cargarla".

Cambio de la función para que esto funcione:

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 

pero se siente sucio. ¿Hay una mejor manera de verificar si un ensamblado ya está cargado y devolverlo a la persona que llama? ¿Los problemas anteriores son específicos de .NET 4.0 o Visual Studio 2010? No he intentado esto fuera del IDE ya que requiere una configuración bastante significativa.

Respuesta

5

Puede comprobar si el conjunto es dinámico omitiendo instancias de AssemblyBuilder. Debería usar Path.GetFileName() para aislar el nombre. Tenga en cuenta que esta no es una buena idea, ya que los ensamblados de diferentes rutas pueden tener nombres idénticos. Pero pareces estar atrapado con esto. Por lo tanto:

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 sensibilidad a las mayúsculas y minúsculas es algo que también debería tratarse.

+0

Esto funciona, gracias. Quité el .ToLower por brevedad, pero tratamos con la sensibilidad de mayúsculas y minúsculas. –

2

Para agregar al anwer de Hans Passant: para mi aplicación (C# 4.0), las instancias de omisión de AssemblyBuilder aún fallaron. Resulta que hay otra clase, System.Reflection.Emit.InternalAssemblyBuilder, que también lanza un NotSupportedException al acceder al Location.

InternalAssemblyBuilder y RuntimeAssembly (el tipo deseado) son tanto internos, por lo que lo mejor que podía llegar a es (en C#):

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

Si usa .Net 4.0, debe verificar Assembly.IsDynamic, que cubre todas las bases –

+0

@DenisTroller, gracias por ese comentario, realmente debería dejarlo como una respuesta :) – Jedidja

0

Si está utilizando .Net 4.0, usted debe comprobar Assembly.IsDynamic, que cubre todas las bases ...

Cuestiones relacionadas