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

C#中如何实现字典与对象属性平级序列化?

问题描述

调用某POST API时,要求的请求体格式如下:

{
 "interval_from": "2001",
 "interval_to": "2011",
 "shift_1": "S1",
 "shift_2": "S2",
 "shift_n": "value"
}

我创建了如下Interval类(使用Newtonsoft.Json特性):

class Interval {
  [JsonProperty("interval_from")]
  public string from {get; set;}

  [JsonProperty("interval_to")]
  public string to {get; set;}
      
  [JsonProperty]
  public Dictionary<string, string> shifts {get; set;}
}

但序列化后结果不符合预期,Dictionary的内容被嵌套在shifts对象中:

{
     "interval_from": "2001",
     "interval_to": "2011",
     "shifts": {
       "shift_1": "S1",
       "shift_2": "S2",
       "shift_n": "value"
     }
}

现有包含序列化逻辑的通用API调用方法,请问有没有替代Dictionary的方案,或实现预期序列化格式的方法?

解决方案

方法1:使用[JsonExtensionData]特性

这是最简便的方案,Newtonsoft.Json的[JsonExtensionData]特性可将Dictionary中的键值对直接序列化到父对象顶层,而非嵌套在子对象中。修改后的类如下:

class Interval {
  [JsonProperty("interval_from")]
  public string from {get; set;}

  [JsonProperty("interval_to")]
  public string to {get; set;}
      
  [JsonExtensionData] // 替换原[JsonProperty]特性
  public Dictionary<string, string> shifts {get; set;}
}

序列化后,shifts内的键值对会直接平摊到根对象中,完全匹配API要求的格式。

方法2:自定义JsonConverter

若需更灵活的控制逻辑,可自定义JsonConverter处理Interval类的序列化:

public class IntervalConverter : JsonConverter<Interval>
{
    public override void WriteJson(JsonWriter writer, Interval value, JsonSerializer serializer)
    {
        writer.WriteStartObject();
        // 序列化固定字段
        writer.WritePropertyName("interval_from");
        serializer.Serialize(writer, value.from);
        writer.WritePropertyName("interval_to");
        serializer.Serialize(writer, value.to);
        // 序列化shifts中的键值对
        if (value.shifts != null)
        {
            foreach (var kvp in value.shifts)
            {
                writer.WritePropertyName(kvp.Key);
                serializer.Serialize(writer, kvp.Value);
            }
        }
        writer.WriteEndObject();
    }

    public override Interval ReadJson(JsonReader reader, Type objectType, Interval existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var jsonObj = JObject.Load(reader);
        var interval = new Interval
        {
            from = jsonObj["interval_from"]?.ToString(),
            to = jsonObj["interval_to"]?.ToString(),
            shifts = new Dictionary<string, string>()
        };
        // 将非固定字段读取到shifts中
        foreach (var prop in jsonObj.Properties())
        {
            if (prop.Name != "interval_from" && prop.Name != "interval_to")
            {
                interval.shifts[prop.Name] = prop.Value.ToString();
            }
        }
        return interval;
    }
}

为Interval类标记使用该转换器:

[JsonConverter(typeof(IntervalConverter))]
class Interval {
  public string from {get; set;}
  public string to {get; set;}
  public Dictionary<string, string> shifts {get; set;}
}

该方案适合需要额外处理逻辑的场景。

方法3:使用动态对象(ExpandoObject)

若无需定义实体类,可直接用ExpandoObject构建请求体:

dynamic requestBody = new ExpandoObject();
requestBody.interval_from = "2001";
requestBody.interval_to = "2011";
requestBody.shift_1 = "S1";
requestBody.shift_2 = "S2";
requestBody.shift_n = "value";

// 序列化动态对象即可得到预期格式
string json = JsonConvert.SerializeObject(requestBody);

该方案适合字段不固定、快速构建请求的场景,但缺少强类型检查。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 00:45:23