Assembly.CreateInstance返回null排查:已在DefinedTypes中找到目标类
Assembly.CreateInstance返回null的问题 结合你提供的跨AppDomain加载程序集并创建实例的代码,虽然能在DefinedTypes中看到目标类,但CreateInstance返回null,常见的原因及解决办法如下:
1. 目标类缺少无参数的公共构造函数
Assembly.CreateInstance(string typeName)默认会尝试调用目标类的无参数公共构造函数。如果你的类只有以下情况:
- 只有私有/受保护的无参构造函数
- 只有带参数的构造函数
- 没有显式定义构造函数但父类的无参构造不可访问
都会导致CreateInstance无法找到可调用的构造函数,从而返回null。
解决办法:
- 给目标类添加一个无参数的公共构造函数:
public class MyTargetClass { // 添加无参公共构造 public MyTargetClass() { } // 其他构造或逻辑 } - 或者使用
CreateInstance的重载,允许调用非公共构造函数:return loadedAssembly.CreateInstance(typeName, true); // 第二个参数允许忽略大小写并访问非公共构造 - 如果需要带参数的构造,使用对应的重载指定参数:
// 假设有一个带string参数的构造 return loadedAssembly.CreateInstance(typeName, false, BindingFlags.Public | BindingFlags.Instance, null, new object[] { "param1" }, null, null);
2. 传入的typeName不是类的完整限定名
你看到DefinedTypes里有目标类,但可能传入的typeName只包含类名,没有包含命名空间,或者存在拼写/大小写错误(默认大小写敏感)。比如目标类的完整限定名是MyApp.Business.MyTargetClass,但你只传了MyTargetClass,就会找不到类型。
解决办法:
从DefinedTypes中获取目标类的FullName,确保传入的typeName完全匹配:
// 先确认类型的完整名称 var targetType = loadedAssembly.DefinedTypes.First(t => t.Name == "MyTargetClass"); string correctTypeName = targetType.FullName; // 用这个正确的名称调用CreateInstance return loadedAssembly.CreateInstance(correctTypeName);
3. 跨AppDomain加载程序集的上下文问题
你的代码中直接在当前AppDomain调用appDomain.Load(assemblyBinary),这里存在一个容易踩坑的点:AppDomain.Load(byte[])返回的Assembly对象是当前AppDomain中的实例,而非目标AppDomain的。这意味着你后续调用loadedAssembly.CreateInstance其实是在当前AppDomain尝试创建实例,而不是目标AppDomain。如果当前AppDomain缺少目标类依赖的其他程序集,或者类型加载上下文存在冲突,就会导致创建失败返回null,但DefinedTypes能看到类型(因为当前域已经加载了程序集的元数据)。
解决办法:
使用AppDomain的CreateInstanceFrom系列方法,或者通过MarshalByRefObject代理在目标AppDomain内部加载程序集:
方法一:使用AppDomain.CreateInstanceFrom
如果程序集文件存在,可以直接用路径加载:
// 假设程序集文件路径为assemblyPath object instance = appDomain.CreateInstanceFrom(assemblyPath, typeName);
方法二:通过代理类在目标域加载
创建一个继承MarshalByRefObject的代理类,让它在目标AppDomain中执行加载和创建实例的逻辑:
public class AssemblyLoader : MarshalByRefObject { public object CreateInstanceFromBinary(byte[] assemblyBinary, string typeName) { Assembly loadedAssembly = Assembly.Load(assemblyBinary); return loadedAssembly.CreateInstance(typeName); } } // 调用方式 AppDomain appDomain = AppDomain.CreateDomain("NewDomain"); AssemblyLoader loader = (AssemblyLoader)appDomain.CreateInstanceAndUnwrap( typeof(AssemblyLoader).Assembly.FullName, typeof(AssemblyLoader).FullName ); object instance = loader.CreateInstanceFromBinary(assemblyBinary, typeName);
这种方式确保程序集是在目标AppDomain中加载,实例也是在目标域创建的,避免了跨域加载的上下文问题。
4. 目标类是抽象类、接口或未闭合的泛型类型
如果目标类是抽象类(abstract)、接口(interface),或者是未指定泛型参数的泛型类型(比如MyGenericClass<T>而你传入的typeName是MyGenericClass),CreateInstance无法实例化这些类型,自然会返回null。
解决办法:
- 确认目标类是可实例化的具体类(非抽象、非接口)
- 如果是泛型类型,传入完整的泛型类型名称,比如
MyNamespace.MyGenericClass1[[System.String, System.Private.CoreLib]](不同框架下格式可能略有差异,建议从Type.FullName`获取正确的名称)
内容的提问来源于stack exchange,提问作者TheLethalCoder

