我想我已经为自己解决了这个问题。
下面的实验
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)。