如何在运行时通过Reflection设置嵌套对象的属性值?
使用Reflection设置嵌套对象属性值
要处理运行时动态创建的嵌套类对象属性赋值,核心思路是递归处理嵌套引用类型,或者解析属性路径逐层赋值。以下是两种实用实现方案:
方案1:递归创建并填充整个对象树
适合从层级化数据源(如嵌套字典)批量构建对象的场景,自动创建所有嵌套对象并赋值:
using System; using System.Collections.Generic; using System.Reflection; public static class ObjectFactory { public static object CreateAndPopulate(Type targetType, Dictionary<string, object> propertyData) { // 创建目标类型实例 var instance = Activator.CreateInstance(targetType); // 遍历所有公共可写实例属性 foreach (PropertyInfo propInfo in targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (!propInfo.CanWrite) continue; var propType = propInfo.PropertyType; // 处理可空值类型,获取底层类型 var underlyingType = Nullable.GetUnderlyingType(propType); var actualType = underlyingType ?? propType; object valueToSet; if (actualType.IsValueType || actualType == typeof(string)) { // 值类型/字符串:直接获取并转换类型 propertyData.TryGetValue(propInfo.Name, out var rawValue); valueToSet = rawValue == null ? null : Convert.ChangeType(rawValue, actualType); } else { // 引用类型(自定义类):递归创建嵌套对象 var nestedData = propertyData.TryGetValue(propInfo.Name, out var nestedRaw) ? nestedRaw as Dictionary<string, object> : new Dictionary<string, object>(); valueToSet = CreateAndPopulate(actualType, nestedData); } propInfo.SetValue(instance, valueToSet); } return instance; } // 泛型包装,方便强类型调用 public static T CreateAndPopulate<T>(Dictionary<string, object> propertyData) { return (T)CreateAndPopulate(typeof(T), propertyData); } }
使用示例
假设存在以下嵌套类:
public class Address { public string City { get; set; } public string ZipCode { get; set; } } public class User { public string Name { get; set; } public int? Age { get; set; } public Address HomeAddress { get; set; } }
调用方式:
var data = new Dictionary<string, object> { {"Name", "张三"}, {"Age", 32}, {"HomeAddress", new Dictionary<string, object> { {"City", "杭州"}, {"ZipCode", "310000"} } } }; User user = ObjectFactory.CreateAndPopulate<User>(data);
方案2:按属性路径设置单个嵌套属性
适合单独设置某个深层嵌套属性的场景,自动创建路径上的空对象:
using System; using System.Reflection; public static class NestedPropertySetter { public static void SetNestedValue(object target, string propertyPath, object value) { string[] propertyNames = propertyPath.Split('.'); object currentObj = target; // 遍历到倒数第二个属性,确保所有中间嵌套对象已实例化 for (int i = 0; i < propertyNames.Length - 1; i++) { PropertyInfo prop = currentObj.GetType().GetProperty(propertyNames[i]); if (prop == null) throw new ArgumentException($"未找到属性:{propertyNames[i]}"); object nestedObj = prop.GetValue(currentObj); if (nestedObj == null) { // 若对象为空,创建实例并赋值 nestedObj = Activator.CreateInstance(prop.PropertyType); prop.SetValue(currentObj, nestedObj); } currentObj = nestedObj; } // 设置最终属性的值 PropertyInfo finalProp = currentObj.GetType().GetProperty(propertyNames[^1]); if (finalProp == null) throw new ArgumentException($"未找到属性:{propertyNames[^1]}"); // 转换值的类型以匹配属性类型 object convertedValue = value == null ? null : Convert.ChangeType(value, finalProp.PropertyType); finalProp.SetValue(currentObj, convertedValue); } }
使用示例
User user = Activator.CreateInstance<User>(); // 设置顶层属性 NestedPropertySetter.SetNestedValue(user, "Name", "李四"); // 设置嵌套属性(自动创建HomeAddress实例) NestedPropertySetter.SetNestedValue(user, "HomeAddress.City", "深圳"); NestedPropertySetter.SetNestedValue(user, "HomeAddress.ZipCode", "518000");
注意事项
- 性能优化:反射操作开销较高,若需高频调用,可缓存类型的
PropertyInfo集合(如用Dictionary<Type, PropertyInfo[]>存储)。 - 自定义类型转换:
Convert.ChangeType仅支持基础类型转换,若需处理自定义类型,需扩展类型转换逻辑。 - 集合/数组:上述方案未处理集合属性,若需支持,可判断属性类型是否实现
IList或ICollection,再创建集合实例并添加元素。
内容的提问来源于stack exchange,提问作者Paul Efford
相关产品推荐
相关产品推荐

