获取实现接口的所有类型

时间:2020-03-05 18:42:58  来源:igfitidea点击:

使用反射,如何以最少的代码获得所有实现与C3.0 / .NET 3.5接口的类型,并最大程度地减少迭代次数?

这是我要重写的内容:

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

解决方案

回答

遍历所有已加载的程序集,遍历所有类型,并检查它们是否实现了接口。

就像是:

Type ti = typeof(IYourInterface);
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) {
    foreach (Type t in asm.GetTypes()) {
        if (ti.IsAssignableFrom(t)) {
            // here's your type in t
        }
    }
}

回答

我在c3.0中会是这样的:)

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

基本上,最少的迭代次数始终是:

loop assemblies  
 loop types  
  see if implemented.

回答

编辑:我刚刚看过编辑,以澄清原来的问题是减少迭代/代码,并且作为练习很好,但是在现实世界中,无论哪种情况,我们都希望最快的实现底层LINQ看起来有多酷。

这是我的Utils方法,用于遍历已加载的类型。它处理常规类和接口,如果要在自己的/第三方代码库中寻找实现,则excludeSystemTypes选项可以极大地加快处理速度。

public static List<Type> GetSubclassesOf(this Type type, bool excludeSystemTypes) {
    List<Type> list = new List<Type>();
    IEnumerator enumerator = Thread.GetDomain().GetAssemblies().GetEnumerator();
    while (enumerator.MoveNext()) {
        try {
            Type[] types = ((Assembly) enumerator.Current).GetTypes();
            if (!excludeSystemTypes || (excludeSystemTypes && !((Assembly) enumerator.Current).FullName.StartsWith("System."))) {
                IEnumerator enumerator2 = types.GetEnumerator();
                while (enumerator2.MoveNext()) {
                    Type current = (Type) enumerator2.Current;
                    if (type.IsInterface) {
                        if (current.GetInterface(type.FullName) != null) {
                            list.Add(current);
                        }
                    } else if (current.IsSubclassOf(type)) {
                        list.Add(current);
                    }
                }
            }
        } catch {
        }
    }
    return list;
}

我承认,这并不漂亮。

回答

没有简单的方法(就性能而言)来完成我们想做的事情。

反射主要与程序集和类型一起使用,因此我们必须获取程序集的所有类型并向其查询正确的接口。这是一个例子:

Assembly asm = Assembly.Load("MyAssembly");
Type[] types = asm.GetTypes();
Type[] result = types.where(x => x.GetInterface("IMyInterface") != null);

这将为我们提供在Assembly MyAssembly中实现IMyInterface的所有类型。

回答

我们可以使用一些LINQ来获取列表:

var types = from type in this.GetType().Assembly.GetTypes()
            where type is ISomeInterface
            select type;

但是,确实更具可读性吗?

回答

要在实现IFoo接口的程序集中查找所有类型,请执行以下操作:

var results = from type in someAssembly.GetTypes()
              where typeof(IFoo).IsAssignableFrom(type)
              select type;

请注意,Ryan Rinaldi的建议是不正确的。它将返回0个类型。你不能写

where type is IFoo

因为type是System.Type实例,所以永远不会是IFoo类型。而是,检查是否可以从该类型分配IFoo。那会得到我们预期的结果。

同样,出于同样的原因,目前被标记为答案的亚当·赖特的建议也是错误的。在运行时,我们会看到0类型返回,因为所有System.Type实例都不是IFoo实现者。

回答

这对我有用(如果我们希望可以在查找中排除系统类型):

Type lookupType = typeof (IMenuItem);
IEnumerable<Type> lookupTypes = GetType().Assembly.GetTypes().Where(
        t => lookupType.IsAssignableFrom(t) && !t.IsInterface);