You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动