代码之家  ›  专栏  ›  技术社区  ›  juan

获取实现接口的所有类型

  •  482
  • juan  · 技术社区  · 16 年前

    使用反射,我如何才能得到所有实现C 3.0/.NET 3.5接口的类型,代码最少,迭代最少?

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

    foreach (Type t in this.GetType().Assembly.GetTypes())
        if (t is IMyInterface)
            ; //do stuff
    
    13 回复  |  直到 16 年前
        1
  •  699
  •   Darren Kopp    11 年前

    我的是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.
    
        2
  •  54
  •   Judah Gabriel Himango    16 年前

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

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

    注意Ryan Rinaldi的建议是错误的。它将返回0个类型。你不能写

    where type is IFoo
    

    因为类型是System.Type实例,并且永远不会是ifoo类型。相反,您要检查ifoo是否可以从类型中赋值。这将得到你期望的结果。

    另外,亚当·赖特的建议(目前标记为答案)也是不正确的,原因也是一样的。在运行时,您将看到0类型返回,因为所有System.Type实例都不是IFOO实现者。

        3
  •  54
  •   Olivier Jacot-Descombes    7 年前

    这对我有用。它循环访问类并检查它们是否从MyInterface中脱离出来。

     foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
                     .Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)))) {
        //do stuff
     }
    
        4
  •  46
  •   Community Keith    7 年前

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

    虽然gettypes()确实会返回所有类型,但并不一定意味着您可以激活它们,从而可能引发 ReflectionTypeLoadException .

    当返回的类型是 derived base 但是 基础 在不同的程序集中定义 衍生的 ,调用程序集未引用的程序集。

    所以说我们有:

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

    然后它会抛出一个 反射类型加载异常 .

    这是因为没有参考 AssemblyA 在里面 汇编语言 您将无法:

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

    换言之 ClassB 不是 可装载的 这是gettypes调用检查和抛出的内容。

    为了安全地限定可加载类型的结果集,然后根据 Phil Haacked 文章 Get All Types in an Assembly Jon 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();
    }
    
        5
  •  19
  •   hillstuk    7 年前

    此处的其他答案使用 IsAssignableFrom . 您也可以使用 FindInterfaces System 命名空间,如前所述 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();
    }
    

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

        6
  •  15
  •   buræquete Naveen Kocherla    7 年前

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

    类似:

    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
  •  8
  •   takrl cck    13 年前

    这对我很有效(如果希望在查找中排除系统类型):

    Type lookupType = typeof (IMenuItem);
    IEnumerable<Type> lookupTypes = GetType().Assembly.GetTypes().Where(
            t => lookupType.IsAssignableFrom(t) && !t.IsInterface); 
    
        8
  •  5
  •   buræquete Naveen Kocherla    7 年前

    编辑:我刚刚看到编辑,澄清了最初的问题是为了减少迭代/代码,这是一个很好的练习,但在现实情况下,你会想要最快的实现,不管基础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;
    }
    

    我承认这不漂亮。

        9
  •  4
  •   Antonin GAVREL    6 年前

    其他答案不适用于 通用接口 .

    这样,只需将typeof(isomeinterface)替换为typeof(t)。

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

    把它们列在清单上。

        10
  •  2
  •   Jorge Córdoba    16 年前

    要想做你想做的事,没有一个简单的方法(就性能而言)。

    反射主要与程序集和类型一起工作,因此您必须获取程序集的所有类型,并查询它们以获得正确的接口。下面是一个例子:

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

    这将获得在程序集myassembly中实现imyinterface的所有类型

        11
  •  0
  •   akop    6 年前

    我在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;
    }
    
        12
  •  0
  •   user489566    6 年前

    在选择装配位置时更好。如果知道所有实现的接口都在同一assembly.definedtype中,则筛选大多数程序集。

    // We get the assembly through the base class
    var baseAssembly = typeof(baseClass).GetTypeInfo().Assembly;
    
    // we filter the defined classes according to the interfaces they implement
    var typeList = baseAssembly.DefinedTypes.Where(type => type.ImplementedInterfaces.Any(inter => inter == typeof(IMyInterface))).ToList();
    

    By Can Bilgin

        13
  •  -3
  •   Ryan Rinaldi    16 年前

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

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

    但是,真的,这更易读吗?