当前位置:  开发笔记 > 编程语言 > 正文

获取实现接口的所有类型

如何解决《获取实现接口的所有类型》经验,为你挑选了8个好方法。

使用反射,如何使用最少的代码获得使用C#3.0/.NET 3.5实现接口的所有类型,并最大限度地减少迭代?

这就是我想要重写的内容:

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

Darren Kopp.. 773

我的将是这个在c#3.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.

请注意,列表还可能包含接口本身.将最后一行更改为`.Where(p => type.IsAssignableFrom(p)&&!p.IsInterface);`将其过滤掉(或`p.IsClass`). (184认同)

注意:这个答案是错误的!这会检查"分配兼容性",而不是接口是否实现.例如`List `没有实现`IEnumerable `但是这个方法将在.Net 4.0中返回true,因为协方差确实是错误的.[正确答案在这里](http://stackoverflow.com/a/12602220/2530848) (37认同)

你是绝对正确的darren,我知道这是一个老线程,我只是注册我的评论只是为了让未来的用户意识到存在这样的问题.不要得罪你.并且问题标题说OP是否要求*获取实现接口的所有类型*此代码不会这样做.但毫无疑问,几乎所有的情况**都有效**.我说的也有角落案件.只是要意识到它; (23认同)

@SriramSakthivel首先关闭,未指定通用值.其次,这个问题早于协方差.第三,你假设协变回报不是他们想要的东西. (19认同)

还需要确保该类不是抽象的=>`.Where(p => type.IsAssignableFrom(p)&& p.IsClass &&!p.IsAbstract` (9认同)


小智.. 60

这对我有用.它循环遍历类并检查它们是否来自myInterface

 foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
                 .Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)))) {
    //do stuff
 }

您假设程序集位于主可执行文件中.不是一个额外的项目.您也通过一堆迭代不必要地迭代.让框架完成繁重的工作会更好.然后在找到时向下过滤.如果相关,请更新您的答案.包括List 推理.var classTypesImplementingInterface = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes()).其中(mytype => typeof(myInterface).IsAssignableFrom(mytype)&& mytype.GetInterfaces().Contains(typeof(myInterface) )); foreach(项目中的var项)Console.Log(item.Name); (4认同)


Judah Gabrie.. 55

要查找实现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.这将获得您的预期结果.

此外,Adam Wright的建议,目前被标记为答案,也是不正确的,并且出于同样的原因.在运行时,您将看到0种类型返回,因为所有System.Type实例都不是IFoo实现者.



1> Darren Kopp..:

我的将是这个在c#3.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.


请注意,列表还可能包含接口本身.将最后一行更改为`.Where(p => type.IsAssignableFrom(p)&&!p.IsInterface);`将其过滤掉(或`p.IsClass`).
注意:这个答案是错误的!这会检查"分配兼容性",而不是接口是否实现.例如`List `没有实现`IEnumerable `但是这个方法将在.Net 4.0中返回true,因为协方差确实是错误的.[正确答案在这里](http://stackoverflow.com/a/12602220/2530848)
你是绝对正确的darren,我知道这是一个老线程,我只是注册我的评论只是为了让未来的用户意识到存在这样的问题.不要得罪你.并且问题标题说OP是否要求*获取实现接口的所有类型*此代码不会这样做.但毫无疑问,几乎所有的情况**都有效**.我说的也有角落案件.只是要意识到它;
@SriramSakthivel首先关闭,未指定通用值.其次,这个问题早于协方差.第三,你假设协变回报不是他们想要的东西.
还需要确保该类不是抽象的=>`.Where(p => type.IsAssignableFrom(p)&& p.IsClass &&!p.IsAbstract`

2> 小智..:

这对我有用.它循环遍历类并检查它们是否来自myInterface

 foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
                 .Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)))) {
    //do stuff
 }


您假设程序集位于主可执行文件中.不是一个额外的项目.您也通过一堆迭代不必要地迭代.让框架完成繁重的工作会更好.然后在找到时向下过滤.如果相关,请更新您的答案.包括List 推理.var classTypesImplementingInterface = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes()).其中(mytype => typeof(myInterface).IsAssignableFrom(mytype)&& mytype.GetInterfaces().Contains(typeof(myInterface) )); foreach(项目中的var项)Console.Log(item.Name);

3> Judah Gabrie..:

要查找实现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.这将获得您的预期结果.

此外,Adam Wright的建议,目前被标记为答案,也是不正确的,并且出于同样的原因.在运行时,您将看到0种类型返回,因为所有System.Type实例都不是IFoo实现者.



4> rism..:

我很欣赏这是一个非常古老的问题,但我想我会为未来的用户添加另一个答案,因为所有日期答案都使用某种形式Assembly.GetTypes.

虽然GetTypes()确实会返回所有类型,但它并不一定意味着你可以激活它们,因此可能会抛出一个ReflectionTypeLoadException.

无法激活类型的典型示例是返回的类型derived来自base但是basederived与调用程序集未引用的程序集不同的程序集中定义.

所以说我们有:

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

如果我们在ClassC其中,AssemblyC那么按照接受的答案做一些事情:

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

然后它会抛出一个ReflectionTypeLoadException.

这是因为没有参考AssemblyA ,AssemblyC你将无法:

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

换句话说ClassB,不能加载,这是对GetTypes的调用检查和抛出的东西.

因此,为了安全地限定可加载类型的结果集,然后根据这个Phil Haacked文章获取程序集中的所有类型和Jon Skeet代码,您将改为执行以下操作:

public static class TypeLoaderExtensions {
    public static IEnumerable 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);
        }
    }
}

然后:

private IEnumerable GetTypesWithInterface(Assembly asm) {
    var it = typeof (IMyInterface);
    return asm.GetLoadableTypes().Where(it.IsAssignableFrom).ToList();
}


这有助于我处理一个超级奇怪的问题,在我的测试项目中GetTypes会失败,只在我们的CI环境中.GetLoadableTypes是此解决方案的修复程序.该错误在本地环境中不可重现,它是:System.Reflection.ReflectionTypeLoadException:无法加载一个或多个请求的类型.检索LoaderExceptions属性以获取更多信息.更具体地说,它抱怨有一种没有具体实施的类型,它发生在单元测试项目中.谢谢你!
万一它对其他人有帮助:这个解决方案对我有用,但是我必须对其进行修改以从列表中删除接口类型。我想为所有它们都激活`CreateInstance`,并且在尝试创建实际接口时引发了异常(当我认为实际接口不适合该解决方案时,这让我感到困惑)。所以我将代码更改为`GetLoadableTypes(assembly).Where(interfaceType.IsAssignableFrom).Where(t =>!(t.Equals(interfaceType)))。ToList();`。

5> hillstuk..:

其他答案在这里使用IsAssignableFrom.您也可以使用FindInterfacesSystem命名空间,如所描述这里.

下面是一个示例,它检查当前正在执行的程序集文件夹中的所有程序集,查找实现某个接口的类(为清楚起见,避免使用LINQ).

static void Main() {
    const string qualifiedInterfaceName = "Interfaces.IMyInterface";
    var interfaceFilter = new TypeFilter(InterfaceFilter);
    var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    var di = new DirectoryInfo(path);
    foreach (var file in di.GetFiles("*.dll")) {
        try {
            var nextAssembly = Assembly.ReflectionOnlyLoadFrom(file.FullName);
            foreach (var type in nextAssembly.GetTypes()) {
                var myInterfaces = type.FindInterfaces(interfaceFilter, qualifiedInterfaceName);
                if (myInterfaces.Length > 0) {
                    // This class implements the interface
                }
            }
        } catch (BadImageFormatException) {
            // Not a .net assembly  - ignore
        }
    }
}

public static bool InterfaceFilter(Type typeObj, Object criteriaObj) {
    return typeObj.ToString() == criteriaObj.ToString();
}

如果要匹配多个接口,可以设置接口列表.



6> angry person..:

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

就像是:

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



7> 小智..:

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

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



8> tags2k..:

编辑:我刚刚看到编辑,以澄清原始问题是减少迭代/代码,这一切都很好,作为一个练习,但在现实世界的情况下,你将希望最快的实现,无论如何底层LINQ看起来有多酷.

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

public static List GetSubclassesOf(this Type type, bool excludeSystemTypes) {
    List list = new List();
    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;
}

我承认,它不漂亮.


枚举器实现IDisposable,它不会在try/finally中处理.最好使用foreach或linq.
推荐阅读
k78283381
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有