简体   繁体   English

Newtonsoft.json解析匿名对象

[英]Newtonsoft.json parsing anonymous objects

I'm having trouble figuring out how to parse a JSON object with anonymous objects. 我在弄清楚如何使用匿名对象解析JSON对象时遇到了麻烦。 Here is my JSON: 这是我的JSON:

{
    "success": true,
    "affectedRows": 2,
    "data": [
        {
            "success": true,
            "affectedRows": 1,
            "data": [
                {
                    "ID": 376,
                    "SomeOtherID": 0,
                    "StringValue": "Fan"
                }
            ]
        },
        {
            "success": true,
            "affectedRows": 1,
            "data": []
        },
        {
            "success": true,
            "data": {
                "ID": 401,
                "DateTime": "2014-10-03 18:52:48"
            }
        }
    ]
}

I have a class that contains classes that work as models for the JSON response I'm expecting. 我有一个包含要用作JSON响应模型的类的类。

public class JSONObjects
{
    public class Success
    {
        public bool success {get;set}
        public int affectedRows {get;set;}
    }

    public class Response
    {
        public int ID {get;set;}
        public int SomeOtherID {get;set;}
        public string StringValue {get;set;}
    }

    public class FirstResponse : Success
    {
        public Response[] data {get;set;}
    }

    public class SecondResponse : Success
    {
        public object[] data {get;set;}
    }

    public class TimeData
    {
        public int ID {get;set;}
        public string DateTime {get;set;}
    }

    public class FullTimeData
    {
        public bool success {get;set;}
        public TimeData data {get;set;}
    }

    public class FullResponse : Success
    {
        // ??? anonymous object[] data ???
    }
}

usage: 用法:

FullResponse data = JsonConvert.DeserializeObject<JSONObjects.FullResponse>(jsonString, jsonSerializerSettings);
Debug.WriteLine(data.data[0].anonymousObject0.data[0].StringValue);

How can I place the anonymous objects in the FullResponse class as an array of objects and then later access them? 如何将匿名对象作为对象数组放置在FullResponse类中,然后在以后访问它们?

Mmm, that's a toughie. 嗯,那是个强硬派。 First off, the only way you can use anonymous types outside the local context in which they were created is to use dynamic . 首先,可以在创建匿名上下文的本地上下文之外使用匿名类型的唯一方法是使用dynamic It is possible to deserialize JSON into wholly dynamic types, but NewtonSoft.Json won't do it out of the box; 可以将JSON反序列化为完全动态的类型,但是NewtonSoft.Json不会开箱即用。 more info can be found here . 更多信息可以在这里找到。 However, I would avoid using dynamic at almost any cost, as it bypasses the most powerful tool a C# developer has for producing correct code; 但是,我会避免使用动态代码,因为它会绕过C#开发人员用来生成正确代码的最强大的工具; the compiler syntax checks. 编译器语法检查。 Fat-finger an identifier, or use square brackets instead of parenthesis on a method call, and as long as it could be valid C# syntax, the compiler will no longer care whether it actually is valid, leaving you to find out at runtime. 肥手指的标识,或使用方括号,而不是括号上的方法调用,只要它可以有效的C#语法,编译器将不再关心它是否真的有效 ,让你在运行时查找。

Staying in static land, the "data" field is going to be your biggest problem in deserializing this, because it's an array type in all but one instance, where it's a struct type. 保持静态状态,“数据”字段将成为反序列化的最大问题,因为在除实例之外的所有实例中,它都是数组类型,而在其中是结构类型。 Without a discriminator of some kind, or a one-to-one relationship between a field name and a field type, I can't think of a way to deserialize this structure into a strongly-typed graph as-is. 如果没有某种区分符,或者没有字段名称和字段类型之间一一对应的关系,我想不出一种将这种结构反序列化为强类型图形的方式。

Let's say that "data" is always an array; 假设“数据”始终是一个数组; the only change in the JSON would be a set of square brackets around the actual data struct for the last object: JSON的唯一变化是在最后一个对象的实际数据结构周围有一组方括号:

{
    "success": true,
    "affectedRows": 2,
    "data": [
        {
            "success": true,
            "affectedRows": 1,
            "data": [
                {
                    "ID": 376,
                    "SomeOtherID": 0,
                    "StringValue": "Fan"
                }
            ]
        },
        {
            "success": true,
            "affectedRows": 1,
            "data": []
        },
        {
            "success": true,
            "data": [
                {
                    "ID": 401,
                    "DateTime": "2014-10-03 18:52:48"
                }
            ]
        }
    ]
}

In that case, what I would do is define a single, self-nesting type that has a property for every data field you could find at any level of this graph: 在这种情况下,我要做的是定义一个单一的,自嵌套的类型,该类型具有一个属性,可在此图的任何级别上找到的每个数据字段:

public class RawResponse
{
    public bool? success {get;set}
    public int? affectedRows {get;set;}

    public int? ID {get;set;}
    public int? SomeOtherID {get;set;}
    public string StringValue {get;set;}
    public string DateTime {get;set;}

    public RawResponse[] data {get;set;}
}

This will allow you to deserialize the JSON into a statically-typed object graph. 这将允许您将JSON反序列化为静态类型的对象图。 Then, you can add a method that produces a particular derived implementation of a Response , based on what fields are set: 然后,您可以添加一种方法,该方法根据设置的字段来生成Response的特定派生实现:

public class RawResponse : Response
{
    public bool? success {get;set}
    public int? affectedRows {get;set;}

    public int? ID {get;set;}
    public int? SomeOtherID {get;set;}
    public string StringValue {get;set;}
    public string DateTime {get;set;}

    public RawResponse[] data {get;set;}

    public Response ToResponse()
    {
        if(ID.HasValue && SomeOtherID.HasValue && StringValue.)
            return new OtherIdResponse{
                                           ID = ID, 
                                           SomeOtherID = SomeOtherID, 
                                           StringValue = StringValue
                                      };

        if(ID.HasValue && DateTime.HasValue)
            return new DateTimeResponse{ID = ID, DateTime = DateTime};

        //default case; success and child data with optional affectedRows
        return new CompoundResponse{
                                       success = success, 
                                       affectedRows = affectedRows, // can be null 
                                       data = data.Select(d=>d.ToResponse())
                                                 .ToArray()
                                   };            
    }
}

Obviously you'll need objects similar to the ones you already have, all derived from a common "response". 显然,您将需要与您已经拥有的对象相似的对象,这些对象均来自一个通用的“响应”。

The last hurdle will be knowing the specific type of any given element. 最后一个障碍将是知道任何给定元素的特定类型。 For that, I recommend a "discriminator"; 为此,我推荐一个“鉴别器”。 a common property providing an easy, unique type identifier: 提供简单,唯一类型标识符的通用属性:

public abstract class Response
{
    public string ReponseTypeName{ get { return GetType().Name; } }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM