使用HostFXR托管可热加载用户C#程序集的C#运行时遇加载异常
问题原因
当UserLibrary.dll调用FunctionLibrary.Module.Test时,CLR无法找到FunctionLibrary.dll。虽然Host.dll已引用并加载了FunctionLibrary,但通过Assembly.Load(byte[])动态加载的UserLibrary,其依赖解析逻辑不会自动复用Host已加载的程序集,也无法定位到FunctionLibrary的存放路径,最终导致找不到依赖的程序集。
解决方案
方案1:注册程序集解析回调
在Host的Main方法开头注册AssemblyResolve事件,当CLR找不到依赖时,手动指定路径加载目标程序集,或返回已加载的程序集:
using System.Reflection; using System.Runtime.InteropServices; using System.Linq; namespace Host; public unsafe class Program { private static byte[] ToMemoryStream( Stream input ) { MemoryStream ms = new MemoryStream(); input.CopyTo( ms ); return ms.ToArray(); } private static Assembly LoadAssembly( string path ) { return Assembly.Load( ToMemoryStream( File.OpenRead( path ) ) ); } [UnmanagedCallersOnly] public static void Main() { // 注册程序集解析回调 AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { // 匹配FunctionLibrary的请求 if (args.Name.StartsWith("FunctionLibrary,")) { // 替换为FunctionLibrary.dll的实际路径 string libPath = @"W:\Visual Studio 2022\FunctionLibrary\bin\Debug\net7.0\FunctionLibrary.dll"; // 直接加载文件返回,或返回已加载的程序集 return Assembly.Load(File.ReadAllBytes(libPath)); // 可选:返回已加载的程序集,避免重复加载 // return AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == args.Name); } return null; }; try { FunctionLibrary.Module.Test = true; Assembly userLibrary = LoadAssembly( @"W:\Visual Studio 2022\UserLibrary\bin\Debug\net7.0\UserLibrary.dll" ); Type? userModule = userLibrary.GetType( "MyLibrary.MyModule" ); MethodInfo entryPoint = userModule?.GetMethod( "OnStartup", BindingFlags.Static | BindingFlags.Public ); entryPoint.Invoke( null, null ); } catch ( Exception ex ) { Console.WriteLine( ex ); } } }
此方案无需移动文件,完全通过代码控制依赖加载逻辑。
方案2:将FunctionLibrary.dll放到CLR默认查找路径
CLR默认会从以下位置查找程序集:
- C++宿主程序的工作目录
UserLibrary.dll所在的目录- GAC
只需将FunctionLibrary.dll复制到上述任意一个目录(比如UserLibrary.dll所在的W:\Visual Studio 2022\UserLibrary\bin\Debug\net7.0\目录),CLR即可自动找到并加载它。
方案3:使用Assembly.LoadFrom加载UserLibrary
替换LoadAssembly方法为Assembly.LoadFrom,它会自动处理当前程序集目录下的依赖:
private static Assembly LoadAssembly( string path ) { return Assembly.LoadFrom(path); }
此方法操作简单,但会锁定目标文件,且依赖程序集必须与UserLibrary.dll在同一目录下,灵活性不如方案1。
内容的提问来源于stack exchange,提问作者user20931801
相关产品推荐
相关产品推荐

