获取实现接口的所有类型
使用反射,如何以最少的代码获取使用 C# 3.0/.NET 3.5 实现接口的所有类型,并最小化迭代?
这就是我想重写的内容:
foreach (Type t in this.GetType().Assembly.GetTypes())
if (t is IMyInterface)
; //do stuff
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?
This is what I want to re-write:
foreach (Type t in this.GetType().Assembly.GetTypes())
if (t is IMyInterface)
; //do stuff
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(19)
您可以使用一些 LINQ 来获取列表:
但实际上,这样更具可读性吗?
You could use some LINQ to get the list:
But really, is that more readable?
OfType Linq 方法完全可以用于这种场景:
https://learn.microsoft.com/fr-fr/dotnet/api/system.linq.enumerable.oftype?view=netframework-4.8
OfType Linq method can be used exactly for this kind of scenarios:
https://learn.microsoft.com/fr-fr/dotnet/api/system.linq.enumerable.oftype?view=netframework-4.8
我在 linq 代码中遇到异常,所以我这样做(没有复杂的扩展):
I got exceptions in the linq-code so I do it this way (without a complicated extension):
如果它对任何人有帮助,这就是我用来使我的一些单元测试更容易的方法:)
If it helps anyone, this is what I'm using to make some of my unit tests easier :)
已经有很多有效的答案,但我想添加花药实现作为类型扩展和单元测试列表来演示不同的场景:
该算法支持以下场景:
There are many valid answers already but I'd like to add anther implementation as a Type extension and a list of unit tests to demonstrate different scenarios:
This algorithm supports the following scenarios:
没有简单的方法(就性能而言)来做你想做的事情。
反射主要适用于程序集和类型,因此您必须获取程序集的所有类型并查询它们以获得正确的接口。 这是一个示例:
这将为您提供在程序集 MyAssembly 中实现 IMyInterface 的所有类型
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:
That will get you all the types that implement the IMyInterface in the Assembly MyAssembly
选择装配位置时效果更好。 如果您知道所有实现的接口都在同一个 Assembly.DefinedTypes 内,则过滤大多数程序集。
作者:Can Bilgin
Even better when choosing the Assembly location. Filter most of the assemblies if you know all your implemented interfaces are within the same Assembly.DefinedTypes.
By Can Bilgin
迄今为止发布的所有答案都考虑了太少或太多的程序集。 您只需检查引用包含该接口的程序集的程序集。 这可以最大程度地减少不必要运行的静态构造函数的数量,并节省大量时间,并在第三方程序集的情况下节省可能出现的意外副作用。
All the answers posted thus far either take too few or too many assemblies into account. You need to only inspect the assemblies that reference the assembly containing the interface. This minimizes the number of static constructors being run unnecessarily and save a huge amount of time and possibly unexpected side effects in the case of third party assemblies.
编辑:我刚刚看到编辑澄清最初的问题是为了减少迭代/代码,这作为练习很好,但在现实情况下,无论如何,你都需要最快的实现底层 LINQ 看起来有多酷。
这是我的 Utils 方法,用于迭代加载的类型。 它可以处理常规类和接口,如果您正在自己/第三方代码库中寻找实现,则 exceptSystemTypes 选项可以极大地加快速度。
我承认这并不漂亮。
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.
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.
It's not pretty, I'll admit.
我在这里看到了很多过于复杂的答案,人们总是告诉我我倾向于使事情变得过于复杂。 同样使用
IsAssignableFrom
方法来解决OP问题是错误的!这是我的示例,它从应用程序域中选择所有程序集,然后获取所有可用类型的平面列表并检查每个类型的接口列表是否匹配:
I see so many overcomplicated answers here and people always tell me that I tend to overcomplicate things. Also using
IsAssignableFrom
method for the purpose of solving OP problem is wrong!Here is my example, it selects all assemblies from the app domain, then it takes flat list of all available types and checks every single type's list of interfaces for match:
其他答案不适用于通用界面。
这个确实如此,只需将 typeof(ISomeInterface) 替换为 typeof (T) 即可。
因此,
我们得到的所有程序集
用于排除接口和抽象程序集,并将
它们放在列表中。
Other answer were not working with a generic interface.
This one does, just replace typeof(ISomeInterface) by typeof (T).
So with
we get all the assemblies
is used to exclude the interface and abstract ones and
to have them in a list.
这对我有用(如果您希望可以在查找中排除系统类型):
This worked for me (if you wish you could exclude system types in the lookup):
循环遍历所有加载的程序集,循环遍历它们的所有类型,并检查它们是否实现了接口。
就像是:
loop through all loaded assemblies, loop through all their types, and check if they implement the interface.
something like:
要查找程序集中实现 IFoo 接口的所有类型:
请注意,Ryan Rinaldi 的建议是不正确的。 它将返回 0 种类型。 您无法编写,
因为 type 是 System.Type 实例,并且永远不会是 IFoo 类型。 相反,您检查 IFoo 是否可以从该类型分配。 这将得到你预期的结果。
此外,亚当·赖特 (Adam Wright) 的建议(目前标记为答案)也是不正确的,原因相同。 在运行时,您将看到返回 0 个类型,因为所有 System.Type 实例都不是 IFoo 实现者。
To find all types in an assembly that implement IFoo interface:
Note that Ryan Rinaldi's suggestion was incorrect. It will return 0 types. You cannot write
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.
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.
这里的其他答案使用
IsAssignableFrom
。 您还可以使用System
命名空间中的FindInterfaces
,如 此处。下面的示例检查当前正在执行的程序集文件夹中的所有程序集,查找实现特定接口的类(为了清楚起见,避免使用 LINQ)。
如果您想匹配多个接口,您可以设置一个接口列表。
Other answers here use
IsAssignableFrom
. You can also useFindInterfaces
from theSystem
namespace, as described here.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).
You can set up a list of interfaces if you want to match more than one.
其他答案使用某种形式的
Assembly.GetTypes
。虽然 GetTypes() 确实会返回所有类型,但这并不一定意味着您可以激活它们,因此可能会抛出
ReflectionTypeLoadException
。无法激活类型的一个典型示例是,返回的类型是从
base
派生的,但base
是在不同的程序集中定义的来自派生
,调用程序集不引用的程序集。假设我们有:
如果在
ClassC
中,它位于AssemblyC
中,那么我们按照接受的答案做一些事情:那么它会抛出一个
ReflectionTypeLoadException
。这是因为如果没有在
AssemblyC
中引用AssemblyA
,您将无法:换句话说,
ClassB
不可加载 这是对 GetTypes 的调用检查并抛出的内容。因此,要安全地限定可加载类型的结果集,请按照这篇 Phil Haacked 文章 获取程序集中的所有类型 和 Jon Skeet代码你会做类似的事情:
然后:
Other answers use some form of
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
.A classic example for not being able to activate a type would be when the type returned is
derived
frombase
butbase
is defined in a different assembly from that ofderived
, an assembly that the calling assembly does not reference.So say we have:
If in
ClassC
which is inAssemblyC
we then do something as per accepted answer:Then it will throw a
ReflectionTypeLoadException
.This is because without a reference to
AssemblyA
inAssemblyC
you would not be able to:In other words
ClassB
is not loadable which is something that the call to GetTypes checks and throws on.So to safely qualify the result set for loadable types then as per this Phil Haacked article Get All Types in an Assembly and Jon Skeet code you would instead do something like:
And then:
这对我有用。 它循环遍历类并检查它们是否派生自 myInterface
This worked for me. It loops though the classes and checks to see if they are derrived from myInterface
我的在 c# 3.0 中是这样的:)
基本上,最少的迭代次数始终是:
Mine would be this in c# 3.0 :)
Basically, the least amount of iterations will always be: