C# 获取实现接口的所有类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26733/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 08:15:15  来源:igfitidea点击:

Getting all types that implement an interface

提问by juan

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?

使用反射,我怎样才能用最少的代码和最小化迭代来获得所有使用 C# 3.0/.NET 3.5 实现接口的类型?

This is what I want to re-write:

这就是我想重写的内容:

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

采纳答案by Darren Kopp

Mine would be this in c# 3.0 :)

我的将是这个在 c# 3.0 :)

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

Basically, the least amount of iterations will always be:

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

loop assemblies  
 loop types  
  see if implemented.

回答by Lasse V. Karlsen

loop through all loaded assemblies, loop through all their types, and check if they implement the interface.

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

something like:

就像是:

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

回答by tags2k

Edit: I've just seen the edit to clarify that the original question was for the reduction of iterations / code and that's all well and good as an exercise, but in real-world situations you're going to want the fastest implementation, regardless of how cool the underlying LINQ looks.

编辑:我刚刚看到了编辑以澄清最初的问题是减少迭代/代码,这作为练习很好,但在现实世界中,你会想要最快的实现,不管底层 LINQ 看起来有多酷。

Here's my Utils method for iterating through the loaded types. It handles regular classes as well as interfaces, and the excludeSystemTypes option speeds things up hugely if you are looking for implementations in your own / third-party codebase.

这是我的 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;
}

It's not pretty, I'll admit.

这不漂亮,我承认。

回答by Jorge Córdoba

There's no easy way (in terms of performance) to do what you want to do.

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

Reflection works with assemblys and types mainly so you'll have to get all the types of the assembly and query them for the right interface. Here's an example:

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

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

That will get you all the types that implement the IMyInterface in the Assembly MyAssembly

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

回答by Ryan Rinaldi

You could use some LINQ to get the list:

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

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

But really, is that more readable?

但真的,这更易读吗?

回答by Judah Gabriel Himango

To find all types in an assembly that implement IFoo interface:

要在实现 IFoo 接口的程序集中查找所有类型:

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

Note that Ryan Rinaldi's suggestion was incorrect. It will return 0 types. You cannot write

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

where type is IFoo

because type is a System.Type instance, and will never be of type IFoo. Instead, you check to see if IFoo is assignable from the type. That will get your expected results.

因为 type 是 System.Type 实例,永远不会是 IFoo 类型。相反,您检查 IFoo 是否可从类型分配。这将得到您预期的结果。

Also, Adam Wright's suggestion, which is currently marked as the answer, is incorrect as well, and for the same reason. At runtime, you'll see 0 types come back, because all System.Type instances weren't IFoo implementors.

此外,Adam Wright 的建议(目前被标记为答案)也是不正确的,原因相同。在运行时,您会看到 0 个类型返回,因为所有 System.Type 实例都不是 IFoo 实现者。

回答by Carl Nayak

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

回答by hillstuk

Other answers here use IsAssignableFrom. You can also use FindInterfacesfrom the Systemnamespace, as described here.

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

Here's an example that checks all assemblies in the currently executing assembly's folder, looking for classes that implement a certain interface (avoiding LINQ for clarity).

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

You can set up a list of interfaces if you want to match more than one.

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

回答by Ben Watkins

This worked for me. It loops though the classes and checks to see if they are derrived from myInterface

这对我有用。它循环遍历类并检查它们是否从 myInterface 派生

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

回答by rism

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.

我很欣赏这是一个非常古老的问题,但我想我会为未来的用户添加另一个答案,因为迄今为止所有的答案都使用某种形式的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.

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

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

无法激活类型的典型示例是当返回的类型derived来自basebase在与 的程序集不同的程序集中定义时derived,调用程序集未引用该程序集。

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 ClassCwhich is in AssemblyCwe then do something as per accepted answer:

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

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

Then it will throw a ReflectionTypeLoadException.

然后它会抛出一个ReflectionTypeLoadException.

This is because without a reference to AssemblyAin AssemblyCyou would not be able to:

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

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

In other words ClassBis not loadablewhich is something that the call to GetTypes checks and throws on.

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

So to safely qualify the result set for loadable types then as per this Phil Haackedarticle Get All Types in an Assemblyand Jon Skeet codeyou would instead do something like:

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

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