我正在从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>();
}
这种方法行吗?有更清洁的方法吗?
答案 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 if
或switch
而不是多个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)
您有两种选择:
使用this answer的dynamic
包或this answer的System.Web
包反序列化为JSON.Net
对象,然后使用条件检查/ null propagation operator访问属性。
自动反序列化到存在差异的级别,然后编写代码以手动反序列化父反序列化对象上正确的POCO类型不同的属性。
使用方法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来打开代码的逻辑路径。