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
相关产品推荐
相关产品推荐

