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

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

public List FindTypesImplementing(string assemblyPath) { var matchingTypes = new List(); 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?

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 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 statement de return fuera del bloque de captura – No estoy muy interesado en que esté allí, pero probablemente sea el código más corto …

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 bash 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.

  ///  /// Get the types within the assembly that match the predicate. /// for example, to get all types within a namespace ///  typeof(SomeClassInAssemblyYouWant).Assembly.GetMatchingTypesInAssembly(item => "MyNamespace".Equals(item.Namespace)) ///  /// The assembly to search /// The predicate query to match against /// The collection of types within the assembly that match the predicate public static ICollection GetMatchingTypesInAssembly(this Assembly assembly, Predicate predicate) { ICollection types = new List(); 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; } 

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

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.