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

如何在C#中使用Newtonsoft将两个属性序列化为一个JSON属性

解决Json.NET序列化时多属性映射同一JSON键的冲突问题

方法一:通过公共属性封装逻辑(最直观的方案)

修改ScanInfo类,将两个版本的字段改为私有,通过一个公共属性统一对外提供非空的扫描结果,序列化时仅处理该属性:

public class ScanInfo
{
    // 私有字段,仅内部维护
    private ScanResult _oldVersion;
    private ScanResultNew _newVersion;

    [JsonProperty("scanResult", NullValueHandling = NullValueHandling.Ignore)]
    public object ScanResult
    {
        get
        {
            // 优先返回新版本,若为空则返回旧版本(可根据需求调整优先级)
            return _newVersion ?? _oldVersion;
        }
        // 如需支持反序列化,可添加赋值逻辑
        set
        {
            if (value is ScanResultNew newResult)
                _newVersion = newResult;
            else if (value is ScanResult oldResult)
                _oldVersion = oldResult;
        }
    }

    // 对外提供设置方法,确保两个版本始终仅存一个非空值
    public void SetOldScanResult(ScanResult result)
    {
        _oldVersion = result;
        _newVersion = null;
    }

    public void SetNewScanResult(ScanResultNew result)
    {
        _newVersion = result;
        _oldVersion = null;
    }
}

这种方案完全规避了属性名冲突,同时通过设置方法保证业务逻辑的一致性,序列化时自然只会输出一个scanResult键。


方法二:自定义ContractResolver(不修改原有类结构)

如果无法改动ScanInfo的原有字段结构,可以通过自定义契约解析器,动态控制序列化行为:

public class ScanInfoContractResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var properties = base.CreateProperties(type, memberSerialization);
        if (type != typeof(ScanInfo))
            return properties;

        // 找到原有两个字段的配置
        var oldVersionProp = properties.First(p => p.UnderlyingName == nameof(ScanInfo.oldVersion));
        var newVersionProp = properties.First(p => p.UnderlyingName == nameof(ScanInfo.newVersion));
        
        // 移除原有冲突的配置
        properties.Remove(oldVersionProp);
        properties.Remove(newVersionProp);

        // 添加自定义的统一属性配置
        var combinedProp = new JsonProperty
        {
            PropertyName = "scanResult",
            NullValueHandling = NullValueHandling.Ignore,
            Readable = true,
            Writable = false, // 不需要反序列化可设为false
            ValueProvider = new ScanResultValueProvider()
        };

        properties.Add(combinedProp);
        return properties;
    }
}

public class ScanResultValueProvider : IValueProvider
{
    public object GetValue(object target)
    {
        var scanInfo = target as ScanInfo;
        // 返回非空的扫描结果
        return scanInfo.newVersion ?? scanInfo.oldVersion;
    }

    public void SetValue(object target, object value)
    {
        // 反序列化逻辑按需实现
        var scanInfo = target as ScanInfo;
        if (value is ScanResultNew newResult)
            scanInfo.newVersion = newResult;
        else if (value is ScanResult oldResult)
            scanInfo.oldVersion = oldResult;
    }
}

使用时需要指定自定义解析器:

var serializerSettings = new JsonSerializerSettings
{
    ContractResolver = new ScanInfoContractResolver()
};
string json = JsonConvert.SerializeObject(yourScanInfoInstance, serializerSettings);

注意事项

不管采用哪种方案,都要保证业务逻辑中oldVersion和newVersion始终仅有一个非空值,避免出现两个结果同时存在时的优先级问题(当前示例中优先返回newVersion,可根据实际需求调整)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 04:15:21