【问题标题】:AssemblyLoadContext, dynamically load an assembly, instantiate an object and cast to a shared interfaceAssemblyLoadContext,动态加载程序集,实例化对象并强制转换为共享接口
【发布时间】:2019-10-02 09:00:46
【问题描述】:

我正在尝试使用AssemblyLoadContext(netcore 3.0 版存在)加载程序集,实例化一个对象并将该对象强制转换为接口,但出现强制转换异常错误。

该接口在加载程序集的项目和实例化的实现之间共享。该对象显然已正确实例化,但是当我执行(T)instance 时出现意外错误。

尝试使用观察者,我能够按照我正在使用的代码和观察者的屏幕截图将实例正确地投射到界面:

private (ExecutionAssemblyLoadContext, T) LoadTheAssemblyAndInstance<T>(string assemblyName, string typeNameToInstance)
{
    var basePath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
    var assemblyContext = new ExecutionAssemblyLoadContext($"{basePath}/{assemblyName}.dll");
    var assembly = assemblyContext.LoadFromAssemblyPath($"{basePath}/{assemblyName}.dll");
    var externalCodeEvent = typeNameToInstance != null ? assembly.ExportedTypes
        .Where(x => x.FullName == typeNameToInstance)
        .Single() : assembly.ExportedTypes.First();
    var instance = Activator.CreateInstance(
            externalCodeEvent,
            _defaultConstructorParameters
        );
    return (assemblyContext, (T)instance);
}

这是完整的异常消息:

System.InvalidCastException:'无法将'Expriva.NewWorkflow.BPMN.ExecutionCodeTest.ExecutionContractTest'类型的对象转换为'Expriva.NewWorkflow.ExternalShared.Interfaces.IExecutionContract'类型。'

下面的截图显示T是由实例实现的

【问题讨论】:

  • 如果你得到一个强制转换异常;返回的对象只是没有实现T
  • 物体实现T,我要加一张照片
  • 添加异常信息
  • 异常表示ExecutionContractTest 没有实现IExecutionContract。请确保这样做。
  • 我确定我发了一张照片,看看编辑后的问题

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


【解决方案1】:

AssemblyLoadContext 支持动态代码加载和卸载,它在自己的 AssemblyLoadContext 实例中创建一个隔离的上下文用于加载代码及其依赖项。

问题是在 ExecutionAssemblyLoadContext 实现中,依赖关系被解决和隔离。使用默认实现,AssemblyLoadContext 的文档表明共享类型不会被隔离。遵循用于共享接口的正确实现。

public class ExecutionAssemblyLoadContext : AssemblyLoadContext
{
    public ExecutionAssemblyLoadContext() : base(isCollectible: true)
    {
    }

    protected override Assembly Load(AssemblyName name)
    {
        return null;
    }
}

【讨论】:

  • 您提供的解决方案是默认的ALC,所以您可以简单地使用:Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath("path/to/plugin");
  • 默认的 ALC 没有标记为可收集,如果你想卸载加载的程序集,这个例子是正确的。如果您不关心卸载,则可以使用默认 ALC。
【解决方案2】:

我也遇到过这个问题,可以把它想象成不同的 AssemblyLoadContext 有自己的已加载类型的副本,因此尽管您可以在两个上下文中引用共享程序集,但就它们而言,所包含的类型是唯一的。

解决方案是在派生的 ALC 中使用 Load override 来解析来自共享上下文的程序集。

例如,如果将共享类型加载到默认 ALC 中,这很简单。

public class ModAssemblyLoadContext : AssemblyLoadContext
{
    public ModAssemblyLoadContext()
        : base("ModAssemblyLoadContext", isCollectible: true)
    {
    }

    protected override Assembly Load(AssemblyName assemblyName)
    {
        return Default.Assemblies
            .FirstOrDefault(x => x.FullName == assemblyName.FullName);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-16
    • 2015-04-11
    • 2013-04-12
    • 1970-01-01
    • 2018-07-31
    • 2014-05-14
    相关资源
    最近更新 更多