2

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

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

在 DNFX 中,这是由 AppDomains 明确定义的,但它们在 netcore 中已被 AssemblyLoadContexts 取代,后者不是程序集执行上下文。

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

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

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

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

4

1 回答 1

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)。

于 2021-02-06T09:04:31.443 回答