You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#类中动态处理JSON对象名称的频繁变更以实现反序列化?

解决C# JSON反序列化中键名称变更的非手动方案

1. 利用System.Text.Json的多别名支持(.NET 7+)

从.NET 7开始,JsonPropertyNameAttribute支持指定多个别名,同一个属性可以匹配JSON中的多个键名,无需修改类结构适配不同版本的JSON。

示例代码:

public class EngineData
{
    [JsonPropertyName("EngineTemp")]
    [JsonPropertyName("EngTemp")]
    public int EngineTemperature { get; set; }
}

// 两种键名均能正常反序列化
var json1 = "{\"EngineTemp\":400}";
var data1 = JsonSerializer.Deserialize<EngineData>(json1);

var json2 = "{\"EngTemp\":400}";
var data2 = JsonSerializer.Deserialize<EngineData>(json2);

该方案适合键名变更少、可提前预判别名的场景,无需额外编写复杂逻辑。

2. 自定义JsonConverter实现灵活键映射

如果键名变更频繁且无法提前预判,可编写自定义JsonConverter,通过维护键名映射字典,自动将不同JSON键映射到目标类的属性上。

示例代码:

public class FlexibleEngineDataConverter : JsonConverter<EngineData>
{
    // 键名映射表:key为JSON可能的键名,value为类属性名
    private readonly Dictionary<string, string> _keyMappings = new()
    {
        {"EngineTemp", nameof(EngineData.EngineTemperature)},
        {"EngTemp", nameof(EngineData.EngineTemperature)},
        // 新增别名只需添加到字典即可
    };

    public override EngineData Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var data = new EngineData();
        using (var doc = JsonDocument.ParseValue(ref reader))
        {
            foreach (var property in doc.RootElement.EnumerateObject())
            {
                if (_keyMappings.TryGetValue(property.Name, out var propName))
                {
                    var prop = typeof(EngineData).GetProperty(propName);
                    prop?.SetValue(data, property.Value.GetInt32());
                }
                // 处理未变更的属性
                else
                {
                    var prop = typeof(EngineData).GetProperty(property.Name);
                    if (prop != null)
                    {
                        var value = JsonSerializer.Deserialize(property.Value.GetRawText(), prop.PropertyType);
                        prop.SetValue(data, value);
                    }
                }
            }
        }
        return data;
    }

    public override void Write(Utf8JsonWriter writer, EngineData value, JsonSerializerOptions options)
    {
        // 序列化时统一输出标准键名
        JsonSerializer.Serialize(writer, new
        {
            EngineTemp = value.EngineTemperature
        });
    }
}

// 使用转换器
var options = new JsonSerializerOptions();
options.Converters.Add(new FlexibleEngineDataConverter());

var json = "{\"EngTemp\":400}";
var data = JsonSerializer.Deserialize<EngineData>(json, options);

该方案无需修改实体类,所有键名映射集中维护,适合大量键名频繁变更的场景。

3. 使用Newtonsoft.Json的自定义ContractResolver(适配Newtonsoft环境)

如果项目使用Newtonsoft.Json,可通过自定义IContractResolver实现多键名匹配。

示例代码:

public class AliasContractResolver : DefaultContractResolver
{
    private readonly Dictionary<string, string> _propertyAliases;

    public AliasContractResolver(Dictionary<string, string> propertyAliases)
    {
        _propertyAliases = propertyAliases;
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        
        // 为属性绑定多个别名
        if (_propertyAliases.TryGetValue(property.PropertyName, out var alias))
        {
            var originalName = property.PropertyName;
            property.PropertyName = null;
            property.ValueProvider = new AliasValueProvider(member, 
                _propertyAliases.Where(kv => kv.Value == originalName).Select(kv => kv.Key).ToList());
        }
        return property;
    }
}

public class AliasValueProvider : IValueProvider
{
    private readonly MemberInfo _member;
    private readonly List<string> _aliases;

    public AliasValueProvider(MemberInfo member, List<string> aliases)
    {
        _member = member;
        _aliases = aliases;
    }

    public void SetValue(object target, object value)
    {
        if (_member is PropertyInfo prop)
            prop.SetValue(target, value);
        else if (_member is FieldInfo field)
            field.SetValue(target, value);
    }

    public object GetValue(object target)
    {
        if (_member is PropertyInfo prop)
            return prop.GetValue(target);
        else if (_member is FieldInfo field)
            return field.GetValue(target);
        return null;
    }
}

// 使用示例
var aliases = new Dictionary<string, string>
{
    {"EngineTemp", "EngineTemperature"},
    {"EngTemp", "EngineTemperature"}
};

var settings = new JsonSerializerSettings
{
    ContractResolver = new AliasContractResolver(aliases)
};

var json = "{\"EngTemp\":400}";
var data = JsonConvert.DeserializeObject<EngineData>(json, settings);

该方案适配已使用Newtonsoft.Json的项目,同样支持集中管理键名映射,避免修改实体类。

内容的提问来源于stack exchange,提问作者Antonio Corneal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 21:30:31