首页 文章

获取实现接口的所有类型

提问于
浏览
467

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

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

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

12 回答

  • 45

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

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

    做你想做的事情没有简单的方法(就性能而言) .

    反射主要用于程序集和类型,因此您必须获取程序集的所有类型并查询它们以获得正确的接口 . 这是一个例子:

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

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

  • -3

    我在linq代码中有例外,所以我这样做(没有复杂的扩展):

    private static IList<Type> loadAllTypes(Types[] interfaces)
    {
        IList<Type> objects = new List<Type>();
    
        // find all types
        foreach (var interfaceType in interfaces)
            foreach (var currentAsm in AppDomain.CurrentDomain.GetAssemblies())
                try
                {
                    foreach (var currentType in currentAsm.GetTypes())
                        if (interfaceType.IsAssignableFrom(currentType) && currentType.IsClass && !currentType.IsAbstract)
                            objects.Add(currentType);
                }
                catch { }
    
        return objects;
    }
    
  • 2

    要查找实现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

    其他答案没有使用 generic interface .

    这个,只需用typeof(T)替换typeof(ISomeInterface) .

    List<string> types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
                .Where(x => typeof(ISomeInterface).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
                .Select(x => x.Name).ToList();
    

    所以

    AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
    

    我们得到了所有的集会

    !x.IsInterface && !x.IsAbstract
    

    用于排除接口和抽象接口

    .Select(x => x.Name).ToList();
    

    将它们列入清单 .

  • 14

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

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

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

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

    但真的,那更具可读性吗?

  • 8

    我的将在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.
    
  • 55

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

    就像是:

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

    其他答案在这里使用 IsAssignableFrom . 您还可以使用 System 命名空间中的 FindInterfaces ,如here所述 .

    下面是一个示例,它检查当前正在执行的程序集文件夹中的所有程序集,查找实现某个接口的类(为清楚起见,避免使用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();
    }
    

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

  • 686

    编辑:我刚刚看到编辑,澄清原始问题是减少迭代/代码,这一切都很好,作为一个练习,但在现实世界的情况下,你将需要最快的实现,无论如何底层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;
    }
    

    我承认,它并不漂亮 .

  • 51

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

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

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

    所以说我们有:

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

    如果 ClassCAssemblyC 中,我们会根据接受的答案做一些事情:

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

    然后它将抛出一个ReflectionTypeLoadException .

    这是因为如果没有 AssemblyC 中对 AssemblyA 的引用,您将无法:

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

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

    因此,为了安全地限定可加载类型的结果集,然后根据Phil Haacked文章Get All Types in an AssemblyJon Skeet code,您将执行以下操作:

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

    然后:

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

相关问题