gpt4 book ai didi

c# - 具有向前和向后兼容性的插件架构

转载 作者:太空狗 更新时间:2023-10-29 23:39:53 24 4
gpt4 key购买 nike

我目前正在研究将使用插件类型系统的 C# 产品。这并不是什么新鲜事,我已经看到了很多关于如何使用接口(interface)轻松实现此功能的信息。

我还看到了通过更新接口(interface)名称来实现向后兼容性的方法,例如:Interface change between versions - how to manage?

关于主 exe 和插件之间的版本不匹配,我可以通过我们的产品预见多种情况。

  • 主程序与插件相同的插件版本
  • 主程序比插件更新
  • 主程序早于插件

  • 从信息中,我已经能够收集到 1 和 2 工作得很好。但是我一直无法弄清楚如何正确实现“向前”兼容性(3)。

    我们的目的是只向插件 API 添加方法。

    任何想法都会有很大帮助。

    最佳答案

    隔离插件API DLL

    首先,您的 PluginAPI(包含接口(interface))应该是主应用程序的单独 DLL。您的主应用程序将引用 PluginAPI,每个插件都将引用 PluginAPI。你很可能已经在这样做了。

    接口(interface)版本控制

    其次,在结构上,每次添加新属性或方法时都应该创建一个新接口(interface)。

    例如:

  • 版本 1: Plugins.IPerson
  • 版本 2: Plugins.V2.IPerson : Plugins.IPerson
  • 版本 3: Plugins.V3.IPerson : Plugins.V2.IPerson

  • 在您决定删除或完全重新设计 API 的极少数情况下,例如:
  • 版本4:Plugins.V4.IPerson//无任何接口(interface)继承

  • 独立插件API DLL 版本控制

    最后,我不是 100% 确定 PluginAPI .dll 的版本控制将如何与接口(interface)版本控制的这种结构体系结构相适应。它可能工作

    或者

    您可能需要为每个版本(每个版本都引用以前的版本)提供匹配的 dll。我们将假设是这种情况。

    案例3的解决方案

    所以现在让我们看看你的案例 [3],主程序比插件更旧:
  • Person Plugin 实现 Plugins.V2.IPlugin 并引用 V3 .dll(只是为了让它有趣)。
  • 主程序引用 V1 .dll
  • 插件文件夹将包含 V2 和 V3 插件 .dll
  • 主应用程序文件夹将仅包含 V1 插件 .dll(以及其他文件)
  • 主应用程序将通过 IPerson 接口(interface)的 V1 定义查找并加载 Person 插件和引用
  • 当然,只有 V1 方法和属性可以从插件访问到主应用程序
  • (可以通过反射访问其他方法 - 不是您想要的)

  • 奖金更新

    什么时候可以使用插件
  • 第三方扩展您的系统。如果这是一个选项,或者如果它是基于网络的,请重定向到他们的 URL,源代码会更好。这是许多软件项目的梦想,但你应该等到你有一个感兴趣的第三方合作伙伴,然后再做额外的工作来构建插件框架。
  • 用户可编辑的“脚本”。您不应该构建自己的脚本语言,而应该针对限制性很强的 appdomain(禁用反射和其他)中的限制性接口(interface)编译用户 c# 代码。
  • 安全分组 - 您的核心软件可能使用受信任的平台调用。风险较高的模块可以分离到另一个库中,并有选择地由最终用户排除。

  • 何时不使用插件

    我是少即是多的倡导者。不要过度设计。如果您正在构建很棒的模块化软件,请使用类和命名空间(不要被接口(interface)带走)。 “模块化”意味着您正在努力遵守 SOLID 原则,但这并不意味着您需要插件架构。在许多情况下,即使是控制反转也是过大的。

    如果您打算将来向第三方开放,请不要将其作为插件架构开始。您可以稍后分阶段构建插件框架:i) 派生接口(interface); ii) 用同一个项目中的接口(interface)定义你的插件; iii) 使用插件加载器类加载您的内部插件; iv) 最后,您可以实现一个外部库加载器。这 4 个步骤中的每一个都让您拥有一个独立的工作系统,并将您推向一个完整的插件系统。

    热插拔插件

    在设计插件架构时,您可能有兴趣知道您可以使插件热插拔:
  • 不释放内存 - 继续加载新插件。这通常很好,除非它可能用于您希望 i) 运行很长时间而不重新启动的服务器软件;并且 ii) 预计在此期间会有许多插件更改和升级。当您在运行时加载插件时,它会将程序集加载到内存中并且无法卸载。原因见[2]。
  • 使用释放内存 - 您可以卸载 AppDomain。 AppDomain 在同一进程中运行,但引用隔离 - 您不能直接引用或调用对象。相反,必须对调用进行编码,并且必须在应用程序域之间序列化数据。如果您不打算经常更改插件,那么增加的复杂性是不值得的,有:i)由于编码/序列化而导致的性能损失,ii)更多的编码复杂性(您不能简单地使用事件、委托(delegate)和方法正常情况下),iii)这都会导致更多错误并使其更难以调试。

  • 因此,如果选项 [2] 吸引您,请先尝试 [1],然后使用该架构,直到遇到 [2] 所需的问题。永远不要过度架构。相信我,我之前在大学期间已经构建了一个 [2] 架构,这很有趣,但在大多数情况下,它可能会过大并可能杀死您的项目(在非业务功能上花费太多时间)。

    关于c# - 具有向前和向后兼容性的插件架构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15443536/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com