Getting all types that implement an interface

2020-01-22 11:47发布

Using reflection, how can I get all types that implement an interface with C# 3.0/.NET 3.5 with the least code, and minimizing iterations?

This is what I want to re-write:

foreach (Type t in this.GetType().Assembly.GetTypes())
    if (t is IMyInterface)
        ; //do stuff

14条回答
啃猪蹄的小仙女
2楼-- · 2020-01-22 12:12

I appreciate this is a very old question but I thought I would add another answer for future users as all the answers to date use some form of Assembly.GetTypes.

Whilst GetTypes() will indeed return all types, it does not necessarily mean you could activate them and could thus potentially throw a ReflectionTypeLoadException.

A classic example for not being able to activate a type would be when the type returned is derived from base but base is defined in a different assembly from that of derived, an assembly that the calling assembly does not reference.

So say we have:

Class A // in AssemblyA
Class B : Class A, IMyInterface // in AssemblyB
Class C // in AssemblyC which references AssemblyB but not AssemblyA

If in ClassC which is in AssemblyC we then do something as per accepted answer:

var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(s => s.GetTypes())
    .Where(p => type.IsAssignableFrom(p));

Then it will throw a ReflectionTypeLoadException.

This is because without a reference to AssemblyA in AssemblyC you would not be able to:

var bType = typeof(ClassB);
var bClass = (ClassB)Activator.CreateInstance(bType);

In other words ClassB is not loadable which is something that the call to GetTypes checks and throws on.

So to safely qualify the result set for loadable types then as per this Phil Haacked article Get All Types in an Assembly and Jon Skeet code you would instead do something like:

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

And then:

private IEnumerable<Type> GetTypesWithInterface(Assembly asm) {
    var it = typeof (IMyInterface);
    return asm.GetLoadableTypes().Where(it.IsAssignableFrom).ToList();
}
查看更多
太酷不给撩
3楼-- · 2020-01-22 12:14

This worked for me (if you wish you could exclude system types in the lookup):

Type lookupType = typeof (IMenuItem);
IEnumerable<Type> lookupTypes = GetType().Assembly.GetTypes().Where(
        t => lookupType.IsAssignableFrom(t) && !t.IsInterface); 
查看更多
登录 后发表回答