.net reflection plugins .net-assembly

.net - c# plugins



Cómo evitar ReflectionTypeLoadException al llamar a Assembly.GetTypes() (4)

¿Has considerado Assembly.ReflectionOnlyLoad ? Teniendo en cuenta lo que estás tratando de hacer, podría ser suficiente.

Estoy intentando escanear un ensamblaje para los tipos que implementan una interfaz específica usando un código similar al siguiente:

public List<Type> FindTypesImplementing<T>(string assemblyPath) { var matchingTypes = new List<Type>(); var asm = Assembly.LoadFrom(assemblyPath); foreach (var t in asm.GetTypes()) { if (typeof(T).IsAssignableFrom(t)) matchingTypes.Add(t); } return matchingTypes; }

Mi problema es que obtengo una ReflectionTypeLoadException al llamar a asm.GetTypes() en algunos casos, por ejemplo, si el ensamblaje contiene tipos que hacen referencia a un ensamblaje que actualmente no está disponible.

En mi caso, no estoy interesado en los tipos que causan el problema. Los tipos que estoy buscando no necesitan los ensamblajes no disponibles.

La pregunta es: ¿es posible omitir / ignorar de algún modo los tipos que causan la excepción pero aún procesar los otros tipos contenidos en el ensamblaje?


Aunque parece que no se puede hacer nada sin recibir la ReflectionTypeLoadException en algún momento, las respuestas anteriores están limitadas en el sentido de que cualquier intento de utilizar los tipos proporcionados por la excepción seguirá generando problemas con el problema original que provocó que el tipo no se cargara.

Para solucionar esto, el siguiente código limita los tipos a aquellos ubicados dentro del ensamblaje y permite que un predicado restrinja aún más la lista de tipos.

/// <summary> /// Get the types within the assembly that match the predicate. /// <para>for example, to get all types within a namespace</para> /// <para> typeof(SomeClassInAssemblyYouWant).Assembly.GetMatchingTypesInAssembly(item => "MyNamespace".Equals(item.Namespace))</para> /// </summary> /// <param name="assembly">The assembly to search</param> /// <param name="predicate">The predicate query to match against</param> /// <returns>The collection of types within the assembly that match the predicate</returns> public static ICollection<Type> GetMatchingTypesInAssembly(this Assembly assembly, Predicate<Type> predicate) { ICollection<Type> types = new List<Type>(); try { types = assembly.GetTypes().Where(i => i != null && predicate(i) && i.Assembly == assembly).ToList(); } catch (ReflectionTypeLoadException ex) { foreach (Type theType in ex.Types) { try { if (theType != null && predicate(theType) && theType.Assembly == assembly) types.Add(theType); } // This exception list is not exhaustive, modify to suit any reasons // you find for failure to parse a single assembly catch (BadImageFormatException) { // Type not in this assembly - reference to elsewhere ignored } } } return types; }


En mi caso, el mismo problema fue causado por la presencia de ensamblajes no deseados en la carpeta de la aplicación. Intente borrar la carpeta Bin y reconstruir la aplicación.


Una manera bastante desagradable sería:

Type[] types; try { types = asm.GetTypes(); } catch (ReflectionTypeLoadException e) { types = e.Types; } foreach (var t in types.Where(t => t != null)) { ... }

Sin embargo, definitivamente es molesto tener que hacer esto. Puede usar un método de extensión para hacerlo más agradable en el código "cliente":

public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) { // TODO: Argument validation try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException e) { return e.Types.Where(t => t != null); } }

Es posible que desee mover la declaración de return fuera del bloque de captura - No estoy muy interesado en que esté allí, pero probablemente sea el código más corto ...