AutoMapper映射Dictionary<string, object>到复杂对象时Address属性为null的问题
解决字典到嵌套类实例的映射问题
我明白你的困扰——当你用带嵌套路径的字典(比如Address.City)映射到Person类时,默认的映射逻辑不会自动帮你实例化嵌套的Address对象,导致这个属性一直是null。下面给你几个实用的解决方案,不管是用第三方库还是手动实现都能解决:
方案1:用AutoMapper自动处理嵌套映射
AutoMapper是.NET生态里常用的映射库,它能自动识别.分隔的嵌套路径,帮你自动实例化嵌套对象。
首先安装AutoMapper包:
Install-Package AutoMapper
然后编写映射代码:
using AutoMapper; // 创建映射配置,只需要声明字典到两个类的映射关系 var config = new MapperConfiguration(cfg => { cfg.CreateMap<IDictionary<string, object>, Person>(); cfg.CreateMap<IDictionary<string, object>, Address>(); }); var mapper = config.CreateMapper(); var values = new Dictionary<string, object>() { ["Address.City"] = "New York", ["FirstName"] = "First Name", ["LastName"] = "Last Name" }; // 执行映射 Person person = mapper.Map<Person>(values); // 此时person.Address.City会被正确赋值为"New York"
AutoMapper会自动解析Address.City路径,先实例化Address对象,再给City属性赋值。
方案2:手动实现嵌套路径的映射逻辑
如果你不想依赖第三方库,可以用反射手动解析路径,自己处理嵌套对象的实例化:
public static T MapDictToNestedObject<T>(IDictionary<string, object> dict) where T : new() { var targetObj = new T(); foreach (var (key, value) in dict) { var propertyPath = key.Split('.'); var currentObj = targetObj; var currentType = typeof(T); // 遍历路径的每一层,直到最后一个属性 for (int i = 0; i < propertyPath.Length - 1; i++) { var prop = currentType.GetProperty(propertyPath[i]); if (prop == null) break; // 如果当前属性是null,就创建对应的实例 if (prop.GetValue(currentObj) == null) { var nestedInstance = Activator.CreateInstance(prop.PropertyType); prop.SetValue(currentObj, nestedInstance); } currentObj = prop.GetValue(currentObj); currentType = prop.PropertyType; } // 给最后一层的属性赋值 var finalProp = currentType.GetProperty(propertyPath.Last()); if (finalProp != null && finalProp.CanWrite) { finalProp.SetValue(currentObj, value); } } return targetObj; } // 使用方法 var values = new Dictionary<string, object>() { ["Address.City"] = "New York", ["FirstName"] = "First Name", ["LastName"] = "Last Name" }; Person person = MapDictToNestedObject<Person>(values);
这个方法通过反射逐层解析路径,自动创建null的嵌套对象,最后完成属性赋值。
方案3:用ExpandoObject+JSON序列化中转
还有一种灵活的思路:先把字典转成带嵌套结构的动态对象,再用JSON序列化库完成映射:
using Newtonsoft.Json; using System.Dynamic; var values = new Dictionary<string, object>() { ["Address.City"] = "New York", ["FirstName"] = "First Name", ["LastName"] = "Last Name" }; // 将字典转成带嵌套结构的ExpandoObject dynamic expandoObj = new ExpandoObject(); var expandoDict = (IDictionary<string, object>)expandoObj; foreach (var (key, value) in values) { var pathParts = key.Split('.'); var currentDict = expandoDict; for (int i = 0; i < pathParts.Length - 1; i++) { if (!currentDict.ContainsKey(pathParts[i])) { currentDict[pathParts[i]] = new ExpandoObject(); } currentDict = (IDictionary<string, object>)currentDict[pathParts[i]]; } currentDict[pathParts.Last()] = value; } // 序列化再反序列化,完成到Person类的映射 var jsonStr = JsonConvert.SerializeObject(expandoObj); Person person = JsonConvert.DeserializeObject<Person>(jsonStr);
这种方法利用JSON序列化库对嵌套对象的处理能力,间接完成字典到嵌套类的映射。
内容的提问来源于stack exchange,提问作者Bruno Avelar




