部分程序进入Main()前加载DLL触发FileNotFoundException的原因及解决方案
问题原因
CLR会在JIT编译方法时,提前加载该方法内部所有类型依赖的程序集,出现未进入Main就加载DLL的核心触发场景包括:
- Main方法内直接引用了共享DLL中的类型,JIT编译Main方法时就会触发DLL加载,此时还没执行到你写的
AssemblyResolve注册逻辑 - Main方法所在类的静态字段、静态构造函数中使用了共享DLL的类型,类型初始化逻辑执行时机早于Main方法
- 程序集层面的特性(Attribute)引用了共享DLL中的类型,程序集加载时就会触发依赖加载
解决方案
核心修改逻辑
保证所有对共享DLL类型的引用,都放在AssemblyResolve注册完成后再被JIT编译加载,具体操作如下:
- 将所有用到共享DLL类型的业务逻辑,封装到独立的方法或类中,不要在Main方法、Main所在类的静态构造/静态字段中直接引用共享DLL的类型
- Main方法仅保留
AssemblyResolve注册逻辑,注册完成后再调用封装了业务逻辑的方法即可
代码示例
错误写法
// 该写法会触发提前加载DLL:Main方法直接引用了共享DLL的SharedDllClass类型,JIT编译Main时就会尝试加载DLL class Program { static void Main() { AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { // 你的共享DLL加载逻辑 return null; }; // 这里直接用到了共享DLL的类型 SharedDllClass.Run(); } }
正确写法
// 该写法可避免提前加载:用到共享DLL的逻辑放在单独方法中,注册完成后才会被JIT编译 class Program { static void Main() { AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { // 你的共享DLL加载逻辑 return null; }; // 注册完成后再调用业务方法 RunBusiness(); } static void RunBusiness() { SharedDllClass.Run(); } }
其他注意事项
- 不要在Main方法所在类的静态字段初始化、静态构造函数中使用共享DLL的类型
- 移除程序集层面引用了共享DLL类型的特性定义
- 若使用C# 9及以上版本,也可将
AssemblyResolve注册逻辑放到模块初始化器中,该逻辑会在Main方法执行前运行,也可解决提前加载问题,但兼容性弱于上述方法
内容的提问来源于stack exchange,提问作者SBB
相关产品推荐
相关产品推荐

