Rozumiem, że to bardzo stare pytanie, ale pomyślałem, że dodam kolejną odpowiedź dla przyszłych użytkowników, ponieważ wszystkie dotychczasowe odpowiedzi wykorzystują jakąś formę Assembly.GetTypes
.
Chociaż GetTypes () rzeczywiście zwróci wszystkie typy, nie musi to oznaczać, że możesz je aktywować, a tym samym potencjalnie wyrzucić ReflectionTypeLoadException
.
Klasycznym przykładem braku możliwości aktywacji typu jest sytuacja, gdy zwracany typ pochodzi derived
z zestawu, base
ale base
jest zdefiniowany w innym zestawie niż zestaw derived
, do którego nie odwołuje się zestaw wywołujący.
Powiedzmy, że mamy:
Class A // in AssemblyA
Class B : Class A, IMyInterface // in AssemblyB
Class C // in AssemblyC which references AssemblyB but not AssemblyA
Jeśli w ClassC
którym jest AssemblyC
, to robimy coś zgodnie z przyjętą odpowiedzią:
var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
Wtedy wyrzuci ReflectionTypeLoadException
.
To dlatego, że bez odniesienia do AssemblyA
w AssemblyC
nie byłby w stanie:
var bType = typeof(ClassB);
var bClass = (ClassB)Activator.CreateInstance(bType);
Innymi słowy ClassB
nie można go załadować co jest sprawdzane i uruchamiane przez wywołanie GetTypes.
Tak aby bezpiecznie zakwalifikować zestaw wyników dla ładowalnych typów wtedy jak na tym Phil Haacked artykule Get Wszystkie rodzaje w zespole i kod Jon Skeet byś zamiast zrobić coś takiego:
public static class TypeLoaderExtensions {
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) {
if (assembly == null) throw new ArgumentNullException("assembly");
try {
return assembly.GetTypes();
} catch (ReflectionTypeLoadException e) {
return e.Types.Where(t => t != null);
}
}
}
I wtedy:
private IEnumerable<Type> GetTypesWithInterface(Assembly asm) {
var it = typeof (IMyInterface);
return asm.GetLoadableTypes().Where(it.IsAssignableFrom).ToList();
}