【问题标题】:Semantics of loading an assembly more than once多次加载程序集的语义
【发布时间】:2021-05-09 11:47:36
【问题描述】:

我正在开发一个插件系统,用户很可能会向命名空间展示包含同名类的新程序集,因为他们正在安装已安装的更新版本。

当您加载包含已由其他已加载程序集定义的类的程序集时,预期的行为是什么?

在 DNFX 中,这由 AppDomains 明确定义,但在 netcore 中,它们已被替换为 AssemblyLoadContexts,它们是不是程序集执行上下文。

当我两次加载同一个程序集时,没有报告异常,但我想知道我是否替换了类或没有任何效果,以及任何其他语义。非常欢迎您提供建议的研究术语或相关文档的链接。

到目前为止,我发现了这个:https://github.com/dotnet/runtime/issues/39783

似乎说使用 AssemblyLoadContexts 可以多次加载程序集,但它没有说明这对于具有相同全名的两个类以及实例化它们的代码意味着什么。

我想当我加载一个程序集对象并将其显式用于 CreateInstance 时,我将获得该程序集中定义的类,但我仍然希望查看有关此的文档。

【问题讨论】:

  • 最好直接在 dotnet/runtime repo 上问这个问题,你更有可能从 MSFT 人员那里得到权威的答案。如果你这样做了,你总是可以在这里交叉发布它作为答案。

标签: c# .net-core assembly-loading


【解决方案1】:

我想我已经自己解决了这个问题。

下面的实验

using System;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;

namespace reload
{
  class Program
  {
    static void Main(string[] args)
    {
      var alc1 = new ALC();
      var alc2 = new ALC();
      Assembly assy1, assy2;
      using (var stream = new FileStream("./assy.dll", FileMode.Open))
        assy1 = alc1.LoadFromStream(stream);
      using (var stream = new FileStream("./assy.dll", FileMode.Open))
        assy2 = alc2.LoadFromStream(stream);
      var currentDomain = AppDomain.CurrentDomain;
      foreach (var item in currentDomain.GetAssemblies())
      {
        Console.WriteLine($"{item.FullName}");
      }
      Console.WriteLine(assy1 == assy2);
    }
  }
  public class ALC : AssemblyLoadContext
  {
    public ALC() : base(isCollectible: true) { }
    protected override Assembly Load(AssemblyName name) => null;

  }
}

产生这个

System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
reload, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Runtime.Loader, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Runtime.Extensions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Console, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
(2) XYZ.StepHandlers, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
False

从这个结果可以清楚地看出,加载了两个不同的XYZ.StepHandlers 程序集,它们不是同一个对象。

查看Assembly.CreateInstance的文档

如果运行时无法在 Assembly 实例中找到 typeName,它会返回 null 而不是抛出异常。

这证实了我的怀疑,即在程序集对象上调用 CreateInstance 会严格解析该程序集对象内的类型。在具有项目引用的程序集的普通代码中,提供程序集的解析取决于一个程序集仅加载一次的假设。

在插件场景中,我们可以违背这个假设。但是我们已经明确引用了程序集,所以没有歧义。


如果您想知道,我不会让他们无偿加载重复项。当我得到一个新的程序集时,我必须加载它以提取程序集名称和版本,并确定它是新的还是替换现有的(更不用说它是否实际上是一个兼容的插件而不是一些随机的 DLL)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-02
    • 1970-01-01
    相关资源
    最近更新 更多