无需重新编译程序集A或B,如何解决TypeLoadException加载类型T问题
解决方案:提前加载兼容动态程序集
针对你的场景,无需重新编译A或B、无需IL重写,可通过提前加载一个与程序集B元数据完全匹配的动态程序集来提供类型T,具体实现逻辑如下:
- 构建与A引用的程序集B完全一致的程序集标识(名称、版本、公钥令牌等,若B为强名称程序集)
- 在动态程序集中定义类型T,确保其完全限定名、成员签名(方法、属性、字段的名称及参数/返回值类型)、访问修饰符与A依赖的T完全兼容
- 在加载程序集A之前,将这个动态程序集加载到当前AppDomain中
当CLR加载A并解析类型T时,会发现已加载的动态程序集中存在匹配的类型,从而成功完成类型绑定,避免TypeLoadException。
代码示例
using System; using System.Reflection; using System.Reflection.Emit; // 1. 构建与目标程序集B完全一致的程序集标识 var targetAssemblyName = new AssemblyName("AssemblyB"); // 若B是强名称程序集,需补充设置公钥令牌和版本: // targetAssemblyName.SetPublicKeyToken(new byte[] { /* B的公钥令牌字节 */ }); // targetAssemblyName.Version = new Version("x.x.x.x"); // 2. 创建动态程序集和模块 var dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly( targetAssemblyName, AssemblyBuilderAccess.Run ); var moduleBuilder = dynamicAssembly.DefineDynamicModule(targetAssemblyName.Name); // 3. 定义与T完全匹配的类型 var typeBuilder = moduleBuilder.DefineType( "YourNamespace.T", // 必须和A引用的T的完全限定名一致 TypeAttributes.Public | TypeAttributes.Class ); // 添加A依赖的成员(示例:无参构造函数、空实现的公开方法) typeBuilder.DefineDefaultConstructor(MethodAttributes.Public); var methodBuilder = typeBuilder.DefineMethod( "DoSomething", MethodAttributes.Public, typeof(void), Type.EmptyTypes ); var ilGenerator = methodBuilder.GetILGenerator(); ilGenerator.Emit(OpCodes.Ret); // 完成类型定义 Type dynamicT = typeBuilder.CreateType(); // 4. 此时加载程序集A,将自动使用动态生成的T Assembly assemblyA = Assembly.LoadFrom(@"path/to/AssemblyA.dll");
关键注意事项
- 动态程序集的标识必须完全匹配A引用的B:程序集名称、版本、文化、公钥令牌缺一不可,否则CLR会判定为不同程序集,无法完成匹配
- 类型T的元数据必须与A依赖的完全兼容:包括完全限定名、成员签名、访问修饰符,否则A调用T的成员时仍会抛出异常
- 该方案基于
System.Reflection.Emit实现,支持所有主流.NET运行时(.NET Framework、.NET Core/.NET 5+),属于纯托管解决方案,无需修改原有程序集或进行IL重写
内容的提问来源于stack exchange,提问作者OwnageIsMagic
相关产品推荐
相关产品推荐

