3

公告告诉我们:

程序集可卸载性是 AssemblyLoadContext 的一项新功能。从 API 的角度来看,这项新功能在很大程度上是透明的,仅通过几个新 API 即可公开。它可以卸载加载程序上下文,释放实例化类型、静态字段和程序集本身的所有内存。应用程序应该能够通过这种机制永远加载和卸载程序集,而不会发生内存泄漏。

此外,该设计说明还提到了“静力学”。

我试过这个简单的测试:

static void Main()
{
    Proxy.X = 15;
    var alc = new AssemblyLoadContext("MyTest", true);
    var asm = alc.LoadFromAssemblyName(typeof(Program).Assembly.GetName());
    var proxy = (Proxy)asm.CreateInstance(typeof(Proxy).FullName);
    Console.WriteLine(proxy.Increment());
}

class Proxy
{
    public static int X;
    public int Increment() => ++X;
}

它输出“16”,表示隔离不起作用。

我的目标是对可以抛出异常的类静态成员进行单元测试。通常的测试可以通过触发类型初始化器来影响彼此的行为,所以我需要以最便宜的方式隔离它们。测试应在 .NET Core 3.0 上运行。

这是正确的方法吗,可以AssemblyLoadContext帮忙吗?

4

1 回答 1

5

是的,它确实隔离了静态变量。

如果我们查看最新的设计说明,我们会看到以下新增内容:

LoadFromAssemblyName

此方法可用于将程序集加载到与当前执行程序集的加载上下文不同的加载上下文中。程序集将被加载到调用该方法的加载上下文中。如果上下文无法在其Load方法中解析程序集,则程序集加载将遵循 默认加载上下文。在这种情况下,即使在非默认上下文中调用了该方法,加载的程序集也可能来自默认上下文

直接在AssemblyLoadContext.Default上调用此方法只会从Default上下文加载程序集。根据调用者的不同,默认值可能与当前执行程序集的加载上下文不同,也可能不同。

此方法不会“强制”将程序集加载到指定的上下文中。它基本上在指定的上下文中启动对指定程序集名称的绑定。该绑定操作将通过完整的绑定解析逻辑,该逻辑可以自由地从任何上下文解析程序集(实际上最可能的结果是指定的上下文或默认上下文)。上面描述了这个过程。

要确保将指定的程序集加载到指定的加载上下文中,请调用AssemblyLoadContext.LoadFromAssemblyPath并指定程序集文件的路径。

这有点令人沮丧,因为现在我需要确定要加载的程序集的确切位置(没有简单的方法可以“克隆”已加载的程序集)。

此代码有效(输出“1”):

static void Main()
{
    Proxy.X = 15;
    var alc = new AssemblyLoadContext("MyTest", true);
    var asm = alc.LoadFromAssemblyPath(typeof(Program).Assembly.Location);
    var proxy = asm.CreateInstance(typeof(Proxy).FullName);
    Console.WriteLine(proxy.GetType().GetMethod("Increment").Invoke(null, null));
}

class Proxy
{
    public static int X;
    public static int Increment() => ++X;
}

(注意,现在我们不能强制转换为Proxy类,因为它与变量的运行时类proxy不同,即使是同一个类......)

于 2019-11-24T21:10:07.140 回答