编译期未知类型参数,如何通过反射设置Dictionary?
解决泛型字典反射赋值的类型不匹配问题
问题原因
当前代码通过IDictionary接口调用Add方法时,虽然接口允许传入object类型,但泛型Dictionary<TKey, TValue>内部会严格校验类型。当TValue是List<int>时,values列表中的元素实际是List<object>,两者属于不同的泛型实例,类型不兼容,因此抛出ArgumentException。
解决方案
需要将keys和values中的每个元素转换为字典要求的目标类型(keyType和valueType),再通过反射调用字典的Add方法添加键值对。
1. 通用类型转换方法
先实现一个方法,将任意object转换为指定目标类型,包括处理泛型集合的情况:
private static object ConvertToTargetType(object source, Type targetType) { if (source == null) return null; // 类型已匹配,直接返回 if (targetType.IsAssignableFrom(source.GetType())) return source; // 处理泛型List<T>的转换 if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(List<>)) { Type elementType = targetType.GetGenericArguments()[0]; IList targetList = (IList)Activator.CreateInstance(targetType); foreach (var item in (IEnumerable)source) { object convertedItem = Convert.ChangeType(item, elementType); targetList.Add(convertedItem); } return targetList; } // 普通类型转换 return Convert.ChangeType(source, targetType); }
2. 修改字典赋值逻辑
通过反射获取字典的Add方法,转换键值类型后调用该方法:
// 创建目标字典实例 var dictionary = Activator.CreateInstance(fieldInfo.FieldType); // 获取字典的泛型Add方法 MethodInfo addMethod = fieldInfo.FieldType.GetMethod("Add"); for (int i = 0; i < keys.Count; i++) { // 转换键到目标类型 object convertedKey = ConvertToTargetType(keys[i], keyType); // 转换值到目标类型 object convertedValue = ConvertToTargetType(values[i], valueType); // 调用Add方法添加键值对 addMethod.Invoke(dictionary, new[] { convertedKey, convertedValue }); } // 将字典赋值给目标字段 fieldInfo.SetValue(mainObj, dictionary);
扩展说明
- 如果
TValue是其他泛型集合(如HashSet<T>),可以扩展ConvertToTargetType方法,添加对应泛型类型的处理逻辑。 - 若转换过程中可能出现类型不兼容(如字符串无法转为int),建议添加
try-catch块处理转换异常。
内容的提问来源于stack exchange,提问作者Arvind Ganesh
相关产品推荐
相关产品推荐

