具有数据类型的 Json.NET 自定义 JsonConverter
Posted
技术标签:
【中文标题】具有数据类型的 Json.NET 自定义 JsonConverter【英文标题】:Json.NET Custom JsonConverter with data types 【发布时间】:2016-08-26 10:54:18 【问题描述】:我偶然发现了一个以以下格式输出 JSON 的服务:
"Author": "me",
"Version": "1.0.0",
"data.Type1":
"Children": [
"data.Type1":
"Children": [
"data.Type2":
"name": "John",
"surname": "Doe"
]
,
"data.Type3":
"dob": "1990-01-01"
]
数据类型名称保留为属性名称,它们的值是实际对象。它们都以data.
前缀开头。
之后我想得到的是这样的:
// Root
"Author": "me",
"Version": "1.0.0",
"Children": [ // Type1
"Children": [ // Type1
// Type2
"Name": "John",
"Surname": "Doe"
]
,
// Type3
"DoB": "1990-01-01"
]
具有以下类:
class Type1
ICollection<object> Children get; set;
class Type2
public string Name get; set;
public string Surname get; set;
class Type3
public DateTime DoB get; set;
class Root
public string Author get; set;
public string Version get; set;
public Type1 Children get; set;
问题
如何将其反序列化为添加的 C# 类,同时考虑数据类型并将它们从树中删除?
我已尝试使用自定义 JsonConverter
,但我正在努力解决如何动态选择转换器,因为最简单的方法是在属性上放置一个属性,但它不受支持。
一个小例子就好了。
【问题讨论】:
【参考方案1】:虽然这种 JSON 格式有点不寻常,并且由于动态属性名称而拒绝使用属性,但仍然可以通过一个小改动将其反序列化为您喜欢的类结构 JsonConverter
:我建议您将Root
类中的Children
属性更改为ICollection<object>
,以镜像Type1
类中的Children
属性。现在,它与您所需输出的结构不匹配(其中Children
显示为数组,而不是对象),否则需要转换器中的其他代码才能正确处理。
class Root
public string Author get; set;
public string Version get; set;
public ICollection<object> Children get; set;
这是我想出的转换器(假设进行了上述更改):
class CustomConverter : JsonConverter
public override bool CanConvert(Type objectType)
return (objectType == typeof(Root));
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
JObject obj = JObject.Load(reader);
Root root = new Root();
root.Author = (string)obj["Author"];
root.Version = (string)obj["Version"];
root.Children = ((Type1)DeserializeTypeX(obj, serializer)).Children;
return root;
private object DeserializeTypeX(JObject obj, JsonSerializer serializer)
JProperty prop = obj.Properties().Where(p => p.Name.StartsWith("data.")).First();
JObject child = (JObject)prop.Value;
if (prop.Name == "data.Type1")
List<object> children = new List<object>();
foreach (JObject jo in child["Children"].Children<JObject>())
children.Add(DeserializeTypeX(jo, serializer));
return new Type1 Children = children ;
else if (prop.Name == "data.Type2")
return child.ToObject<Type2>(serializer);
else if (prop.Name == "data.Type3")
return child.ToObject<Type3>(serializer);
throw new JsonSerializationException("Unrecognized type: " + prop.Name);
public override bool CanWrite
get return false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
throw new NotImplementedException();
有了这个转换器,你可以像这样反序列化你的类:
Root root = JsonConvert.DeserializeObject<Root>(json, new CustomConverter());
然后您可以像这样序列化为新格式:
JsonSerializerSettings settings = new JsonSerializerSettings
DateFormatString = "yyyy-MM-dd",
Formatting = Formatting.Indented
;
Console.WriteLine(JsonConvert.SerializeObject(root, settings));
小提琴:https://dotnetfiddle.net/ESNMLE
【讨论】:
【参考方案2】:不确定这是否可行,但您是否尝试过使用 Newtonsoft.Json 序列化对象并在类属性中包含 JsonProperty 标记?我知道这在将 Json 反序列化为类时会起作用。
<JsonProperty("user_id")>
Public Property UserID As String
//Converts Json user_id: 123 to class.UserID = 123
要使用 Newtonsoft 进行序列化,首先将 Newtonsoft 包含到项目中,然后
Dim stringJson As String = Newtonsoft.Json.JsonConvert.SerializeObject(root)
【讨论】:
感谢您的回答。我试过了,但问题是,整个层级都必须被移除和替换,因为它们只是作为数据来区分它们所代表的类型,其中JsonProperty只是在类名和json属性名之间进行映射。以上是关于具有数据类型的 Json.NET 自定义 JsonConverter的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Json.Net 序列化/反序列化具有附加属性的自定义集合