使用反射动态解析插件中的类型 [英] Resolve types from plugins dynamically using reflection

查看:85
本文介绍了使用反射动态解析插件中的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

嘿,



我正在编写一段代码,将传入的json消息反序列化为类。这种情况非常普遍且众所周知。我正在实现一个Command设计模式,它根据匹配的标识符学习目标类类型。我愿意拥有我的系统支持插件(能够实现协议抽象命令,甚至在我的数据库中创建表 - 我能想到的最好的例子是拥有多种身份验证方法)。



每个继承自某个多态基类的类都有一个带有唯一标识符的属性。一旦遇到标识符,解串器就会查看Id-> Type缓存,或者在所有已加载的程序集的类型中找到具有匹配标识符的类。



让我们想象一下系统正在变暖,它首先加载基本模块(可执行程序直接需要的程序集)。然后,突然,用户使用某种身份验证方法发送登录请求(未加载,因为它没有在任何主程序集中实现。)



未加载身份验证扩展,因为它从未被引用,因此,反序列化将失败。



有没有一种优雅的方法来解决这个问题,而无需手动配置插件(我假设如果某个目录中存在插件dll,则应该激活它)。



非常感谢!

Hey,

I'm writing a piece of code that deserializes incoming json messages into classes. The scenario is pretty common and well-known. I'm implementing a Command design pattern, which learns the target class type, according to a matched identifier. I'm willing to have my system support plugins (that would be capable of implementing protocol abstract commands, and even create tables in my database - the best example I can think of is having several authentication methods).

Every class that inherits from a certain polymorphic base class, has an attribute with its unique identifier. Once an identifier is encountered the deserializer is looking at an Id->Type cache, or finds the class with the matching identifier within the types of all the loaded assemblies.

Lets imagine that the system is warming up, it starts by loading the essential modules (which are the assemblies the executable needs directly. Then, suddenly, a user sends a login request using a certain authentication method (which is not loaded, as it is not implemented in any of the main assemblies).

The authentication extension is not loaded, as it was never referenced, therefore, the deserialization would fail.

Is there an elegant way to solve this problem, without having to configure the plugins manually (I assume that if a plugin dll exists in a certain directory, it should be activated).

Thanks a lot!

推荐答案

首先,你应该避免任何名字,是因为它需要使用字符串常量,编译器无法检查。这样,任何使用名称的解决方案都会对维护非常不利。



真正好的选择是定义插件接口并通过插件实现它。在这种方法中,主机程序集的反射代码查找所有或某些类型的插件程序集,并检查是否实现了插件接口。如果它被实现,实现类型由主机实例化并通过接口引用使用(并且仅通过接口引用)。



但我还使用了额外的缩短搜索实现类型的技术。我还开发了一个程序集级属性,用于插件程序集并声明哪些类型实现了哪些插件接口。这也是可靠的,因为属性参数可以是 System.Type 类型。但是,.NET不允许基于 System.Type 区分类型,例如基类型(缺少的功能称为元类,但这是不是一个地方现在认真讨论它)。因此,主机程序集加载一个可能的插件并查看此属性。如果不存在,则不是插件。 (如果加载失败,这甚至不是针对兼容框架版本的.NET程序集,或者根本不是.NET程序集,因此也不是插件。)然后,检查类型。如果所述实现类型确实实现了所述接口,并且如果该接口是主机所期望的,则这是有效的插件。然后实现类型在一个步骤中实例化,无需任何搜索。



您可以在我过去的答案中找到其他详细信息:

通过它的字符串表示从集合中收集类型 [ ^ ],

C#现有实例上的Reflection InvokeMember [ ^ ],

动态加载用户控件 [ ^ ]。



这个一切都很简单。如果由于某种原因,您需要您的插件不仅可以加载,而且还可以卸载,那么复杂的部分就会启动。由于.NET出于安全原因不允许卸载程序集,因此应使用单独的应用程序域,并且通过应用程序域边界工作要困难得多,需要使用IPC。如果你有这种情况,请提出一个后续问题,这也是一个可以解决的问题,甚至更难。



-SA
First of all, you should avoid doing it by any names, because it will require using string constants, which cannot be checked up by the compiler. This way, any solution using names will be really bad for maintenance.

The really good option is to define "plug-in interfaces" and implement it by plug-ins. In this approach, the reflection code of the host assembly looks for all or some types of a plug-in assemblies and checks up if the plug-in interfaces is implemented or not. If it is implemented, the implementing type is instantiated by the host and used through the interface reference (and only through the interface reference).

But I also used an additional technique to shorten up the search for implementing type(s). I also developed an assembly-level attribute which is used in a plug-in assembly and claims what types implement what plug-in interfaces. This is also reliable, because the attribute parameter can be of the type System.Type. However, .NET does not allow to discriminate types based on System.Type based on, say, base type (the missing feature is called "meta-classes", but this is not a place do discuss it seriously now). So, the host assembly loads a would-be-plug-in and looks at this attribute. If it is not present, this is not a plug-in. (If load was failed, this is not even a .NET assembly targeted to a compatible framework version or not a .NET assembly at all, so also not a plug-in.) Then, the types are checked up. If the said implementing type really implements the said interface, and if this interface is what is expected by the host, this is a valid plug-in. And then the implementing type is instantiated in a single step, without any search.

You can find other detail in my past answers:
Gathering types from assemblies by it's string representation[^],
C# Reflection InvokeMember on existing instance[^],
Dynamically Load User Controls[^].

This is all pretty simple. The complex part starts if, by some reason, you need your plug-ins to be not only loadable, but also unloadable. As .NET does not allow to unload an assembly for security reasons, separate Application Domains should be used, and working through the Application Domains boundary is much harder, requires IPC. If you have such situations, please ask a follow-up question, this is also a solvable problem, even somewhat harder one.

—SA


这篇关于使用反射动态解析插件中的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆