如何创建构造函数需委托参数的泛型类型实例?反射创建MessageParser<T>遇错求助
解决反射创建泛型
MessageParser<T>时的构造函数参数问题 你遇到的两个问题核心都是编译时类型未知导致的,咱们一步步拆解解决:
第一个错误:MessageParser<> does not have a parameterless constructor
这个逻辑很直接——你的MessageParser<T>类只定义了带Func<T>参数的构造函数,根本没有无参构造函数,所以调用Activator.CreateInstance(genericType)(不传参数)自然会触发运行时错误,这部分你判断得完全正确。
第二个错误:Cannot convert lambda expression to type 'string' because it is not a delegate type
这是因为编译器无法推断你传入的lambda要转换成什么委托类型。Activator.CreateInstance的第二个参数是object[],当你直接传() => Activator.CreateInstance(typeArgument)时,由于T是反射得到的编译时未知类型,编译器不知道这个lambda应该对应Func<T>委托,所以会尝试转换成默认的object类型,进而抛出类型转换错误。
正确解决方案:通过反射创建Func<T>委托
因为T是运行时才确定的类型,我们需要用反射来构建符合Func<T>签名的委托实例,再传给Activator.CreateInstance。具体步骤如下:
- 先获取
Func<T>的委托类型:
Type typeArgument = itemInstance.GetType(); Type funcType = typeof(Func<>).MakeGenericType(typeArgument);
- 创建对应
Func<T>的委托实例,这里利用Activator.CreateInstance<T>方法构建工厂委托:
// 获取Activator.CreateInstance<T>()的泛型方法 MethodInfo createInstanceMethod = typeof(Activator) .GetMethod("CreateInstance", Type.EmptyTypes) .MakeGenericMethod(typeArgument); // 将方法转换为Func<T>委托 Delegate factoryDelegate = Delegate.CreateDelegate(funcType, createInstanceMethod);
- 最后用这个委托作为参数创建
MessageParser<T>实例:
Type genericClass = typeof(MessageParser<>); Type genericType = genericClass.MakeGenericType(typeArgument); var instance = Activator.CreateInstance(genericType, factoryDelegate);
备选方案:用表达式树构建委托
如果你的typeArgument有公共无参构造函数,也可以用表达式树来构建工厂委托,代码更直观:
// 获取T的无参构造函数 ConstructorInfo ctor = typeArgument.GetConstructor(Type.EmptyTypes); if (ctor == null) { throw new InvalidOperationException($"{typeArgument.Name} 没有公共无参构造函数"); } // 构建表达式树:() => new T() var lambda = Expression.Lambda(funcType, Expression.New(ctor)); Delegate factoryDelegate = lambda.Compile(); // 后续创建实例的代码和之前一致 var instance = Activator.CreateInstance(genericType, factoryDelegate);
额外:调用ParseFrom方法
如果后续需要调用ParseFrom,同样需要通过反射(因为编译时不知道T的类型):
// 获取ParseFrom方法 MethodInfo parseMethod = genericType.GetMethod("ParseFrom"); byte[] data = /* 你的字节数组数据 */; // 调用方法并转换返回值 var result = parseMethod.Invoke(instance, new object[] { data });
内容的提问来源于stack exchange,提问作者BohdanZPM
相关产品推荐
相关产品推荐

