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

如何处理JSON中含动态日期属性的对象?附结构示例

碰到这种带动态日期后缀的JSON属性确实头疼,总不能每次新增日期都手动加属性对吧?我给你分享几个实用的解决方案,都是C#里处理这类动态JSON的常用手段:

方法一:利用Json扩展属性(推荐,简单高效)

不管你用的是Newtonsoft.Json(Json.NET)还是System.Text.Json,都支持扩展属性特性,能把那些未在类中定义的动态属性统一收集到一个字典里,之后我们再把这些属性转换成方便使用的日期-布尔值映射。

针对Newtonsoft.Json的实现

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;

public class RootObject
{
    public string id { get; set; }
    public string name { get; set; }
    public string type { get; set; }
    // 这里保留你的其他固定属性(TypeBlock、AddressBlock等)

    // 用JsonExtensionData标记,收集所有未定义的属性
    [JsonExtensionData]
    private IDictionary<string, JToken> _dynamicProperties;

    // 提供一个只读属性,把动态日期属性转换成易读的字典
    public Dictionary<DateTime, bool?> ExceptionalDays
    {
        get
        {
            var exceptionalDays = new Dictionary<DateTime, bool?>();
            foreach (var kvp in _dynamicProperties)
            {
                // 筛选出exceptionalDay开头的属性
                if (kvp.Key.StartsWith("exceptionalDay_"))
                {
                    // 提取日期字符串并转换格式
                    var datePart = kvp.Key.Replace("exceptionalDay_", "").Replace("_", "-");
                    if (DateTime.TryParse(datePart, out DateTime date))
                    {
                        // 把JToken转换成bool?类型
                        exceptionalDays[date] = kvp.Value.ToObject<bool?>();
                    }
                }
            }
            return exceptionalDays;
        }
    }
}

针对System.Text.Json的实现

System.Text.Json的扩展属性要求字典类型为Dictionary<string, JsonElement>,处理逻辑稍作调整:

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

public class RootObject
{
    public string id { get; set; }
    public string name { get; set; }
    public string type { get; set; }
    // 其他固定属性...

    [JsonExtensionData]
    private Dictionary<string, JsonElement> _dynamicProperties;

    public Dictionary<DateTime, bool?> ExceptionalDays
    {
        get
        {
            var exceptionalDays = new Dictionary<DateTime, bool?>();
            foreach (var kvp in _dynamicProperties)
            {
                if (kvp.Key.StartsWith("exceptionalDay_"))
                {
                    var datePart = kvp.Key.Replace("exceptionalDay_", "").Replace("_", "-");
                    if (DateTime.TryParse(datePart, out DateTime date))
                    {
                        // 根据JsonElement的类型转换bool?
                        exceptionalDays[date] = kvp.Value.ValueKind switch
                        {
                            JsonValueKind.True => true,
                            JsonValueKind.False => false,
                            JsonValueKind.Null => null,
                            _ => null
                        };
                    }
                }
            }
            return exceptionalDays;
        }
    }
}

方法二:自定义JSON转换器(灵活可控)

如果需要更精细的控制(比如序列化时也要把字典转成动态日期属性),可以自定义一个JsonConverter,手动处理每个属性的读写逻辑:

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

public class RootObjectConverter : JsonConverter<RootObject>
{
    public override RootObject Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var root = new RootObject();
        var exceptionalDays = new Dictionary<DateTime, bool?>();

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject)
                break;

            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                var propName = reader.GetString();
                reader.Read();

                // 处理固定属性
                switch (propName)
                {
                    case "id":
                        root.id = reader.GetString();
                        break;
                    case "name":
                        root.name = reader.GetString();
                        break;
                    case "type":
                        root.type = reader.GetString();
                        break;
                    // 这里添加其他固定属性的处理逻辑
                    default:
                        // 处理动态日期属性
                        if (propName.StartsWith("exceptionalDay_"))
                        {
                            var datePart = propName.Replace("exceptionalDay_", "").Replace("_", "-");
                            if (DateTime.TryParse(datePart, out DateTime date))
                            {
                                bool? value = null;
                                switch (reader.TokenType)
                                {
                                    case JsonTokenType.True:
                                        value = true;
                                        break;
                                    case JsonTokenType.False:
                                        value = false;
                                        break;
                                    case JsonTokenType.Null:
                                        value = null;
                                        break;
                                }
                                exceptionalDays[date] = value;
                            }
                        }
                        break;
                }
            }
        }

        root.ExceptionalDays = exceptionalDays;
        return root;
    }

    public override void Write(Utf8JsonWriter writer, RootObject value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        // 序列化固定属性
        writer.WriteString("id", value.id);
        writer.WriteString("name", value.name);
        writer.WriteString("type", value.type);
        // 其他固定属性...

        // 把ExceptionalDays转换成动态日期属性
        foreach (var kvp in value.ExceptionalDays)
        {
            var propName = $"exceptionalDay_{kvp.Key:yyyy_MM_dd}";
            if (kvp.Value.HasValue)
                writer.WriteBoolean(propName, kvp.Value.Value);
            else
                writer.WriteNull(propName);
        }

        writer.WriteEndObject();
    }
}

// 使用时需要在序列化/反序列化时指定转换器
// 比如:
// var options = new JsonSerializerOptions();
// options.Converters.Add(new RootObjectConverter());
// var root = JsonSerializer.Deserialize<RootObject>(jsonStr, options);

选择建议

  • 如果只是需要反序列化读取数据,方法一(扩展属性)足够简单,代码量少,推荐优先使用。
  • 如果需要双向序列化(把C#对象转回原格式的JSON)或者有特殊的属性处理逻辑,方法二的自定义转换器更灵活。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:42:53