首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >从DESerialize JSON到c#对象的动态转换

从DESerialize JSON到c#对象的动态转换
EN

Stack Overflow用户
提问于 2019-06-26 07:39:59
回答 3查看 99关注 0票数 1

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

例如,如果问题Id是"37“,则它是一个Address对象。

我有如下格式的JSON字符串

代码语言:javascript
复制
"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#属性

代码语言:javascript
复制
public Dictionary<int, answer> answers{ get; set; }

然后我有一个通用的答案类

代码语言:javascript
复制
public class answer
{
    public string name { get; set; }
    public dynamic answer { get; set; }
}

如果你看看json的答案数据,你会发现每个问题的答案都是不同的。例如,一个答案是ADDRESS对象,另一个答案是名字和姓氏对象。

我的问题是,如何自动将json反序列化为正确的对象/属性?我可以创建不同的POCO对象,比如address和ProfileName,但是我如何将它们自动映射到正确的对象/属性。

编辑:

Loop through all Answers

代码语言:javascript
复制
        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>();


}

这种方法可以吗?有没有更干净的方法呢?

EN

回答 3

Stack Overflow用户

发布于 2019-06-26 08:31:06

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

代码语言:javascript
复制
    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。如果你有很多答案,这可以提高性能。

票数 2
EN

Stack Overflow用户

发布于 2019-06-26 11:28:14

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

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

只需这样声明您的answers字典:

代码语言:javascript
复制
public Dictionary<int, JToken> Answers{ get; set; }

然后,当您需要地址页面时,您可以简单地执行Answers[37].ToObject<Address>()。如何调用此方法取决于代码的其余部分,但您可以将其嵌入到属性中,在一个大开关中,在多个方法中,每个类一个。我喜欢的一个选择是在每个可反序列化的类中都有一个静态From方法:

代码语言:javascript
复制
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.Net的默认反序列化设置是不区分大小写的,因此可以将name属性从JSON反序列化为POCOs上更常用的Name属性。

票数 2
EN

Stack Overflow用户

发布于 2019-06-26 08:34:29

您有几个选项:

  1. 使用System.Web包(根据this answer )或JSON.Net包(根据this answer )将其反序列化为System.Web对象,然后使用条件检查/ null propagation operator访问property.
  2. Automatically反序列化到存在差异的级别,然后使用代码手动将不同的属性反序列化为JSON.Net (OnDeserializing或OnDeserialized)提供的Serialization Callbacks之一上的正确POCO类型,以将不同属性作为反序列化管道的一部分填充到正确的类型中。<代码>H213<代码>G214

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

代码语言:javascript
复制
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来打开代码的逻辑路径。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56763348

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档