如何干净地反序列化JSON,其中字符串值包装在同名对象中

我想将一些奇怪的JSON反序列化为C#类:

{ "Result": { "Client": { "ProductList": { "Product": [ { "Name": { "Name": "Car polish" } } ] }, "Name": { "Name": "Mr. Clouseau" }, "AddressLine1": { "AddressLine1": "Hightstreet 13" } } } } 

json2csharp为JSON生成以下类:

 public class Name { public string Name { get; set; } } public class Product { public Name Name { get; set; } } public class ProductList { public List Product { get; set; } } public class Name2 { public string Name { get; set; } } public class AddressLine1 { public string AddressLine1 { get; set; } } public class Client { public ProductList ProductList { get; set; } public Name2 Name { get; set; } public AddressLine1 AddressLine1 { get; set; } } public class Result { public Client Client { get; set; } } public class RootObject { public Result Result { get; set; } } 

问题是对象中的重复属性名称( ProductClient NameClient中的AddressLine1 )迫使我创建一个只有一个字符串属性( NameAddressLine1 )的额外类,以便能够反序列化JSON。

生成的代码也是无效的,因为成员名称不能与其封闭类型相同(但我知道可以使用[JsonProperty(PropertyName = "Name")]属性来解决。

什么是避免类层次结构中不必要的级别并具有干净的类结构以便能够使用JSON.NET反序列化此JSON的最佳方法? 请注意,这是第三方API,因此我不能只更改JSON。

实际上,这是API结果的一种奇怪格式,使其更难以消费。 解决问题的一个想法是创建一个自定义JsonConverter ,它可以获取包装值并返回内部值,就像包装器不在那里一样。 这将允许您将笨重的JSON反序列化为更合理的类层次结构。

这是一个应该工作的转换器:

 class WrappedObjectConverter : JsonConverter { public override bool CanConvert(Type objectType) { return true; } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JToken token = JToken.Load(reader); // Get the value of the first property of the inner object // and deserialize it to the requisite object type return token.Children().First().Value.ToObject(objectType); } public override bool CanWrite { get { return false; } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } } 

使用此转换器,您可以创建一个类层次结构,以消除额外的嵌套级别。 您必须使用[JsonConverter]属性标记需要“解包”的属性,以便Json.Net知道何时应用自定义转换器。 这是改进的类结构:

 public class RootObject { public Result Result { get; set; } } public class Result { public Client Client { get; set; } } public class Client { [JsonConverter(typeof(WrappedObjectConverter))] public List ProductList { get; set; } [JsonConverter(typeof(WrappedObjectConverter))] public string Name { get; set; } [JsonConverter(typeof(WrappedObjectConverter))] public string AddressLine1 { get; set; } } public class Product { [JsonConverter(typeof(WrappedObjectConverter))] public string Name { get; set; } } 

(请注意,如果Result对象除了Client之外不包含任何其他属性,您也可以在那里应用WrappedObjectConverterClient移动到RootObject并删除Result类。)

这是一个演示转换器的演示:

 class Program { static void Main(string[] args) { string json = @" { ""Result"": { ""Client"": { ""ProductList"": { ""Product"": [ { ""Name"": { ""Name"": ""Car polish"" } } ] }, ""Name"": { ""Name"": ""Mr. Clouseau"" }, ""AddressLine1"": { ""AddressLine1"": ""Hightstreet 13"" } } } }"; RootObject obj = JsonConvert.DeserializeObject(json); Client client = obj.Result.Client; foreach (Product product in client.ProductList) { Console.WriteLine(product.Name); } Console.WriteLine(client.Name); Console.WriteLine(client.AddressLine1); } } 

输出:

 Car polish Mr. Clouseau Hightstreet 13 

听起来您可能对实现自定义JsonConverter 。 这是一个网站 ,里面有一些如何做到这一点的样本。 这是一个相当简单的过程,可以让你保持你所坚持的JSON,同时拥有你最熟悉的任何类结构。