将JSON反序列化为c#对象

时间:2019-06-25 23:39:58

标签: c# .net json

我正在从Web服务获取JSON数据。它为我提供了具有不同问题和答案的表格数据every answer is a different c# object。我正在尝试找到映射答案以更正c#对象的最佳方法。

例如,如果问题ID为“ 37”,则其为地址对象。

我下面有这种格式的JSON字符串

"answers": {
    "37": {
              "name": "yourAddress37",
              "order": "6",
              "sublabels": "{\"cc_firstName\":\"First Name\",\"cc_lastName\":\"Last Name\",\"cc_number\":\"Credit Card Number\",\"cc_ccv\":\"Security Code\",\"cc_exp_month\":\"Expiration Month\",\"cc_exp_year\":\"Expiration Year\",\"addr_line1\":\"Street Address\",\"addr_line2\":\"Street Address Line 2\",\"city\":\"City\",\"state\":\"State \\/ Province\",\"postal\":\"Postal \\/ Zip Code\",\"country\":\"Country\"}",
              "text": "Your Home Address:",
              "type": "control_address",
              "answer": {
                "addr_line1": "148 east 38st ",
                "addr_line2": "",
                "city": "Brooklyn ",
                "state": "Ny",
                "postal": "11203",
                "country": ""
              },
              "prettyFormat": "Street Address: 148 east 38st <br>City: Brooklyn <br>State / Province: Ny<br>Postal / Zip Code: 11203<br>"
            },
     "38": {
              "name": "emergencyContact",
              "order": "9",
              "sublabels": "{\"prefix\":\"Prefix\",\"first\":\"First Name\",\"middle\":\"Middle Name\",\"last\":\"Last Name\",\"suffix\":\"Suffix\"}",
              "text": "Emergency Contact Name:",
              "type": "control_fullname",
              "answer": {
                "first": "Pauline ",
                "last": "Sandy "
              },
              "prettyFormat": "Pauline  Sandy "
            }
}

并映射到以下c#属性

public Dictionary<int, answer> answers{ get; set; }

然后我有一个通用的Answer类

public class answer
{
    public string name { get; set; }
    public dynamic answer { get; set; }
}

如果您查看json中的ANSWER数据,那么对于每个问题,都会看到不同的数据。例如,一个答案将是ADDRESS OBJECT,另一个答案将是FIRST&LAST NAME对象。

我的问题是,我如何自动将json反序列化为正确的对象/属性?我可以创建不同的POCO对象,例如地址和配置文件名称,但是我将如何自动将它们映射到正确的对象/属性。

编辑:

Loop through all Answers

        foreach (var a in item.answers)
        {
            // pass the ANSWER OBJECT (dynamic data type) to function
            createNewApplication(System.Convert.ToInt16(a.Key), a.Value.answer,ref app);               

        }


private void createNewApplication(int key, dynamic value,ref HcsApplicant app)
{

    if (key == 4) // data is plain string
        app.yourPhone = value;
    if (key == 8)
        app.yourEmail = value;
    if (key==37) // data is a object
        app.address = value.ToObject<address>();


}

这种方法行吗?有更清洁的方法吗?

3 个答案:

答案 0 :(得分:2)

为每个通过解析JSON对象字符串构造的答案类型构造一个构造函数。使所有答案都实现一个接口,例如我回答。将所有构造函数(作为函数)映射到字典中的相应问题ID。最后,遍历问题,调用每个构造函数,然后将它们放入新词典中。 示例代码:

    interface IAnswer { };

    public class ExampleAnswer : IAnswer
    {
        public ExampleAnswer(String JSONObject)
        {
            // Parse JSON here
        }
    }

    delegate IAnswer AnswerConstructor(String JSONObject);

    Dictionary<int, AnswerConstructor> Constructors = new Dictionary<int, AnswerConstructor>()
    {
        {1234, ((AnswerConstructor)(json => new ExampleAnswer(json)))}
        // Add all answer types here
    };

    Dictionary<int, IAnswer> ParseAnswers(Dictionary<int, String> JSONObjects)
    {
        var result = new Dictionary<int, IAnswer>();
        foreach (var pair in JSONObjects)
            result.Add(pair.Key, Constructors[pair.Key](pair.Value));

        return result;
    }

编辑:看看马特(Matt)的答案,其中提供了一些不错的方法来解析JSON。

Edit2,作为对您的编辑的回应:看来这是一种好方法!我认为这比我的回答要好,因为与我的方法不同,您可以保留所有类型的信息。

我唯一可能要更改的就是使用else ifswitch而不是多个if。如果您有很多答案,这可以提高性能。

答案 1 :(得分:2)

我个人不喜欢涉及自定义分析并直接查看问题的每个选项。

您可以通过JToken类使用部分反序列化。

只需这样声明您的resize()字典:

answers

然后,每当需要地址页时,您都可以简单地进行public Dictionary<int, JToken> Answers{ get; set; } 。如何调用此方法取决于代码的其余部分,但是您可以将其嵌入属性中,进行大的切换,使用多种方法,每个类一个。我喜欢的一种选择是在每个可反序列化的类中都有一个静态Answers[37].ToObject<Address>()方法:

From

请注意,Json.Net的默认反序列化设置不区分大小写,因此您可以将public class Address { public string Name { get; set; } // all the othe properties // .... public static Address From(Dictionary<int, JToken> answers) { return answers?.TryGetValue(37, out var address) ?? false ? address?.ToObject<Address>() : null; } } // so you can just write: var address = Address.From(answers); 属性从JSON反序列化为POCO上更惯用的name属性。 / p>

答案 2 :(得分:1)

您有两种选择:

  1. 使用this answerdynamic包或this answerSystem.Web包反序列化为JSON.Net对象,然后使用条件检查/ null propagation operator访问属性。

  2. 自动反序列化到存在差异的级别,然后编写代码以手动反序列化父反序列化对象上正确的POCO类型不同的属性。

  3. 利用JSON.Net提供的Serialization Callbacks(OnDeserializing或OnDeserialized)之一来处理将不同的属性填充为反序列化管道的一部分的正确类型。

使用方法2和3,您可以在POCO上编写一个更好的辅助方法,该方法检查对象的属性并返回结果,该结果将是所设置的类型(我建议返回一个Enum),例如:

public PropertyTypeEnum GetPropertyType(MyPocoClass myPocoClass)
{
    if (myPocoClass.PropertyOne != null)
    {
        return PropertyTypeEnum.TypeOne;
    }
    else if (...)
    {
        return PropertyTypeEnum.TypeN
    }
    else
    {
        // probably throw a NotImplementedException here depending on your requirements
    }
}

然后在代码中使用该对象,可以使用返回的Enum来打开代码的逻辑路径。