Come prevenire ReflectionTypeLoadException quando si chiama Assembly.GetTypes ()

Sto provando a scansionare un assieme per tipi che implementano un’interfaccia specifica usando un codice simile a questo:

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; } 

Il mio problema è che ottengo un ReflectionTypeLoadException quando si chiama asm.GetTypes() in alcuni casi, ad esempio se l’assembly contiene tipi che fanno riferimento a un assembly che al momento non è disponibile.

Nel mio caso, non sono interessato ai tipi che causano il problema. I tipi che sto cercando non hanno bisogno degli assembly non disponibili.

La domanda è: è ansible in qualche modo saltare / ignorare i tipi che causano l’eccezione, ma elaborare ancora gli altri tipi contenuti nell’assieme?

Un modo abbastanza brutto potrebbe essere:

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

È decisamente fastidioso doverlo fare però. È ansible utilizzare un metodo di estensione per renderlo più bello nel codice “client”:

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

Potresti desiderare di spostare la dichiarazione di return dal blocco di cattura – non sono molto entusiasta di esserci io stesso, ma probabilmente è il codice più breve …

Benché a un certo punto non si possa fare nulla senza ricevere ReflectionTypeLoadException, le risposte di cui sopra sono limitate in quanto qualsiasi tentativo di utilizzare i tipi forniti dall’eccezione causerà ancora problemi con il problema originale che ha causato il caricamento del tipo.

Per superare questo problema, il codice seguente limita i tipi a quelli che si trovano all’interno dell’assieme e consente a un predicato di restringere ulteriormente l’elenco di tipi.

  ///  /// 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; } 

Hai considerato Assembly.ReflectionOnlyLoad ? Considerando quello che stai cercando di fare, potrebbe essere abbastanza.

Nel mio caso, lo stesso problema era causato dalla presenza di assembly indesiderati nella cartella dell’applicazione. Prova a svuotare la cartella Bin e ribuild l’applicazione.