【问题标题】:Are optional library references possible? (for moddable Mods) [duplicate]可选的库引用是否可能? (对于可修改的 Mod)[重复]
【发布时间】:2016-11-20 08:53:37
【问题描述】:

有什么方法可以告诉 Visual Studio 为我构建一个 .dll,仅当它存在但仍将其作为参考时才加载另一个引用(托管)库?

基本上,我希望能够从外部库中的类继承,并且只有当外部类存在时,我才会对其进行初始化。

更长的解释:

  • 我已经使用 modding api 制作了一个游戏(通过 Assembly.LoadFrom)
  • 我希望模组是可模组化的。假设我有 2 个 mod A 和 Mod B。Mod A 提供了一个静态注册表来添加附加功能。因此,在 Mod B 中,我目前正在检查是否加载了 Mod A,如果是,则使用 Mod As 静态注册表来注册我的添加。
  • 问题是,为了避免编译错误,我必须在 Visual Studio 项目中为 Mod B 添加 Mod A 作为参考 - 如果 Mod A 不存在,这会导致 Mod B 无法加载。但它应该是一个可选的参考:/

像“懒惰的库引用”这样的东西是完美的 - 只有在实际需要时才加载库引用。

【问题讨论】:

    标签: c# .net visual-studio


    【解决方案1】:

    您应该了解 MEF 的工作原理 (Managed Extensibility Framework),因为它的设计考虑了这种插件场景。

    这也是您应该考虑如何围绕接口而不是继承来安排抽象的地方。我敢肯定,你可能可以用动态类型和反射做一些聪明的事情,但我也认为这很可能会变得复杂,因此同时容易出错。

    您还可以使用Lazy<T> 来确保仅在需要时通过延迟实例化外部依赖项来加载内容。您也不必添加对这些插件 dll 的静态引用。您可以扫描目录以查找实现抽象接口定义的库和类型。

    我也有点担心为什么你会让一个抽象依赖于另一个在某种程度上听起来有问题的抽象(Mod B 检查 Mod A)——可以说是“泄漏”的抽象。

    如果您确实需要让这些插件协同工作,您可以使用自定义属性方法,以便 mod 可以声明依赖项。

    public class ModDependency : Attribute
    {
        public string DependsOn { get; set; }
    }
    

    但最终您将在主应用程序代码中进行一些协调,然后在运行时提供对这些插件的实例引用。

    【讨论】:

    • 是的,我想避免使用反射/动态类型。谢谢,我会读入 MEF
    • 就像上面提到的 TypeBuilder 的注释一样,都是关于反射的,所以这个选项不在桌面上。我会调查更改您当前的方法以启用可以在这些外部依赖项中实现的interface
    • 感谢您提供的附加信息 - 我认为 Lazy 不会起作用,因为 CLR 似乎会尝试加载引用的库,甚至不创建相关类的实例(也不是访问任何静态变量)。看起来只要有任何类使用引用的库,它就会尝试加载引用的库,即使该类根本没有使用。
    • 每个模组已经可以声明必备依赖和可选依赖,确保它们以正确的顺序加载。
    • 当然,这就是 .NET 通常的工作方式,一旦加载了 DLL,它就无法卸载,但 Lazy 将推迟类型的实际初始化。
    【解决方案2】:

    “.Net 中的程序集由 CLR 按需加载。通常,在使用该程序集类型的 JIT 方法之前不会尝试加载程序集。” (来自不同的SO Answer

    我知道!显然我可以应用我的可选依赖方法!

    我发现问题是由于我加载这些模组的方式引起的。我正在遍历所有程序集类型,检查任何实现 IMod 的类,这显然导致加载有问题的类并且需要 CLR 加载依赖项。

    我现在没有调用assembly.GetTypes(),而是调用assembly.GetExportedTypes() 并将相关类声明为内部类。现在,如果依赖项不存在,则永远不会加载它。

    【讨论】:

    • 不,它不会“加载类”(您不能“加载”类)它会将 DLL 加载到当前的AppDomain 中以检索 DLL 中的类列表通过元数据。只有在使用 new 关键字时才会创建对象。一旦 DLL 被加载到 AppDomain 中,它就不能被卸载。做到这一点并且能够卸载 DLL 的唯一方法是在单独的 AppDomain 中完成所有这些操作。
    • 是的,但它似乎只在有问题的类第一次被引用时才尝试加载引用的库。因此,只要没有人接触该类,它就永远不会加载引用的库
    猜你喜欢
    • 1970-01-01
    • 2019-04-24
    • 2019-08-12
    • 2020-03-20
    • 2015-12-27
    • 2014-09-07
    • 1970-01-01
    • 1970-01-01
    • 2010-12-13
    相关资源
    最近更新 更多