You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6加载互相引用的程序集时遇FileNotFoundException如何解决

问题描述

我有一个C# .NET 6项目,在进程内编译两个程序集,其中一个程序集引用另一个。当我创建引用其他程序集的对象实例,或尝试调用其方法时,收到以下错误:

System.IO.FileNotFoundException: 'Could not load file or assembly 'mydll.dll, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified

通过AppDomain.CurrentDomain.GetAssemblies()返回的列表可以确认两个程序集都已加载,但仍报错。

尝试过两种实现方式,均出现错误:

方式一:使用AppDomain.CurrentDomain.CreateInstance

var assembly = AppDomain.CurrentDomain.Load(assemblyData); // 字节数组形式的程序集数据

foreach (var library in buildState.AllReferences)
{
    AppDomain.CurrentDomain.Load(library.CompiledData); // 加载引用的程序集字节数组
}

var assemblies = AppDomain.CurrentDomain.GetAssemblies(); // 确认两个程序集已加载

// 错误在此行抛出
var runner = AppDomain.CurrentDomain.CreateInstance($"{@namespace}.dll", $"{@namespace}.{className}").Unwrap() as ITemplateRunner;

if (runner == null)
    throw new Exception($"{className} is not a ITemplateRunner");

await runner.Execute();

方式二:使用Activator.CreateInstance

var assembly = Assembly.Load(assemblyData);

foreach (var library in buildState.AllReferences)
{
    var t = Assembly.Load(library.CompiledData);
}

var assemblies = AppDomain.CurrentDomain.GetAssemblies();

var runner = Activator.CreateInstance(assembly.GetType($"{@namespace}.{className}") ?? throw new Exception($"{@namespace}.{className} not in compiled dll.")) as ITemplateRunner;

if (runner == null)
    throw new Exception($"{className} is not a ITemplateRunner");

// 错误在此行抛出
await runner.Execute();

编辑1:调用assembly.CreateInstance()时,两种方式都会出现相同的错误提示。


解决方案

核心问题是:即便通过字节数组加载了程序集,CLR解析依赖时仍会优先尝试从磁盘路径查找,而非直接使用内存中已加载的程序集。以下是几种可行的解决方法:

1. 注册AssemblyResolve事件

在加载程序集前,给当前AppDomain注册AssemblyResolve事件,当CLR找不到程序集时,从已加载的集合中匹配返回:

// 先注册事件,再加载程序集
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
    return AppDomain.CurrentDomain.GetAssemblies()
        .FirstOrDefault(a => a.FullName == args.Name);
};

// 加载程序集逻辑不变
var assembly = Assembly.Load(assemblyData);
foreach (var library in buildState.AllReferences)
{
    Assembly.Load(library.CompiledData);
}

// 创建实例
var runner = Activator.CreateInstance(assembly.GetType($"{@namespace}.{className}")) as ITemplateRunner;
// ...后续逻辑

2. 使用AssemblyLoadContext(.NET 6+推荐)

.NET Core及后续版本推荐用AssemblyLoadContext管理内存程序集,它能自动处理依赖解析,更适配现代.NET架构:

var loadContext = new AssemblyLoadContext(null, isCollectible: false);

// 先加载依赖程序集
foreach (var library in buildState.AllReferences)
{
    using var stream = new MemoryStream(library.CompiledData);
    loadContext.LoadFromStream(stream);
}

// 再加载主程序集
using var mainStream = new MemoryStream(assemblyData);
var assembly = loadContext.LoadFromStream(mainStream);

// 创建实例
var runner = Activator.CreateInstance(assembly.GetType($"{@namespace}.{className}")) as ITemplateRunner;
// ...后续逻辑

3. 将程序集写入临时目录

如果上述方法不适用,可把字节数组写入临时文件夹,让CLR能从磁盘找到程序集:

var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempDir);

// 写入依赖程序集
foreach (var library in buildState.AllReferences)
{
    var dllPath = Path.Combine(tempDir, $"{library.AssemblyName}.dll");
    File.WriteAllBytes(dllPath, library.CompiledData);
}

// 写入主程序集
var mainDllPath = Path.Combine(tempDir, $"{mainAssemblyName}.dll");
File.WriteAllBytes(mainDllPath, assemblyData);

// 从磁盘加载程序集
var assembly = Assembly.LoadFrom(mainDllPath);
var runner = Activator.CreateInstance(assembly.GetType($"{@namespace}.{className}")) as ITemplateRunner;
// ...后续逻辑

// 程序结束后可清理临时文件
// Directory.Delete(tempDir, recursive: true);

内容的提问来源于stack exchange,提问作者BJury

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 03:16:19