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

C# 如果字符串值包装在同名对象中,如何干净地反序列化JSON,c#,json,json.net,deserialization,C#,Json,Json.net,Deserialization,我想将一些奇怪的JSON反序列化到C#类: 为JSON生成以下类: public class Name { public string Name { get; set; } } public class Product { public Name Name { get; set; } } public class ProductList { public List<Product> Product { get; set; } } public class

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

为JSON生成以下类:

public class Name
{
    public string Name { get; set; }
}

public class Product
{
    public Name Name { get; set; }
}

public class ProductList
{
    public List<Product> 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; }
}
公共类名
{
公共字符串名称{get;set;}
}
公共类产品
{
公共名称名称{get;set;}
}
公共类产品列表
{
公共列表产品{get;set;}
}
公共类名称2
{
公共字符串名称{get;set;}
}
公共类地址行1
{
公共字符串AddressLine1{get;set;}
}
公共类客户端
{
公共产品列表产品列表{get;set;}
公共名称2名称{get;set;}
公共地址行1地址行1{get;set;}
}
公开课成绩
{
公共客户端{get;set;}
}
公共类根对象
{
公共结果结果{get;set;}
}
问题是对象中重复的属性名称(
Product
中的
Name
Client
Client
中的
AddressLine1
)迫使我创建一个只有一个字符串属性(
Name
AddressLine1
)的额外类,以便能够反序列化JSON

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


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

听起来您可能对实现自定义的
JsonConverter
感兴趣。这有一些你如何做到这一点的例子。这是一个相当简单的过程,可以让您在拥有自己最熟悉的类结构的同时保留所使用的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<JProperty>().First().Value.ToObject(objectType);
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}
(请注意,如果
结果
对象将不包含除
客户端
之外的任何其他属性,则可以在那里应用
WrappedObjectConverter
,并将
客户端
向上移动到
根对象
并消除
结果
类。)

下面是一个演示,演示了转换器的工作情况:

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<RootObject>(json);

        Client client = obj.Result.Client;
        foreach (Product product in client.ProductList)
        {
            Console.WriteLine(product.Name);
        }
        Console.WriteLine(client.Name);
        Console.WriteLine(client.AddressLine1);
    }
}

删除其中一个名称或名称2。不能更改json生成过程吗?如果输出更干净,这可能是一个更好的解决方案!不,我不能更改JSON。这是从一个公共休息室收到的。这对我来说是一个很好的开始,谢谢!我的嵌套属性并不是唯一的,这增加了复杂性。所以我有解析所有字段的方法,但要特别对待这一字段。这里有一个例子:“地址”:{“@attributes”:{“地址类型”:“prop”},“地址”:“12街”,“城市”:“B”,“州”:“MD”,“邮政编码”:“12”,“国家”:“美国”、“电子邮件”:fu@fu.co}为什么我们需要重复“Name”和“AddressLine1”。我们不能让反序列化程序使用更简单的字符串,例如:{“Result”:{“Client”:{“ProductList”:[{“Name”:“Car polish”}],“Name”:“Clouseau先生”,”AddressLine1:“Hightstreet 13”}}@当然是progLearner;理想的解决方案是使JSON更简单、更易于使用。问题是JSON通常由第三方API控制,因此作为消费者,您必须按原样处理它,除非您能够说服API提供商对其进行更改。这个答案的重点是展示如何处理有缺陷的JSON if你不能更改。非常感谢,我创建了以下帖子:
public class RootObject
{
    public Result Result { get; set; }
}

public class Result
{
    public Client Client { get; set; }
}

public class Client
{
    [JsonConverter(typeof(WrappedObjectConverter))]
    public List<Product> 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; }
}
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<RootObject>(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