我正在使用外部API,它根据计数返回属性作为数组或对象。处理这个问题的好方法是什么?
以数组形式返回:
{
"contacts": {
"address": [
{
"id": "47602070",
"type": "Work",
"street": "MyStreet",
"city": "MyCity",
"zip": "12345",
"country": "USA"
},
{
"id": "47732816",
"type": "GPS",
"street": "50.0,30.0"
}
]
}
}
作为对象返回:
{
"contacts": {
"address": {
"id": "47602070",
"type": "Work",
"street": "MyStreet",
"city": "MyCity",
"zip": "12345",
"country": "USA"
}
}
}
我认为解决方法是使用自定义反序列化器并返回一个长度为1的数组用于对象大小写,并为数组大小写默认反序列化,但我不知道该怎么做。
我尝试将对象反序列化为一个数组,并希望Json.net能为我处理这个案例,但没有骰子。
答案 0 :(得分:5)
基于Christophe Geers'answer,这就是我最终要做的事情。
创建自定义JSON转换器,始终将JSON解析为数组。如果JSON是非数组对象,则反序列化该对象并将其包装在数组中。
使用自定义转换器属性标记相应的属性。
自定义转换器
public class JsonToArrayConverter<T> : CustomCreationConverter<T[]>
{
public override T[] Create(Type objectType)
{
// Default value is an empty array.
return new T[0];
}
public override object ReadJson(JsonReader reader, Type objectType, object
existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.StartArray)
{
// JSON object was an array, so just deserialize it as usual.
object result = serializer.Deserialize(reader, objectType);
return result;
}
else
{
// JSON object was not an arry, so deserialize the object
// and wrap it in an array.
var resultObject = serializer.Deserialize<T>(reader);
return new T[] {resultObject};
}
}
}
问题示例的数据结构
public class Organisation
{
public Contacts contacts;
}
public class Address
{
public string id;
public string street;
public string city;
public string type;
public string zip;
public string country;
}
public class Contacts
{
// Tell JSON.net to use the custom converter for this property.
[JsonConverter(typeof(JsonToArrayConverter<Address>))]
public Address[] address;
}
答案 1 :(得分:3)
自定义JSON.NET转换器可能会在这里发挥作用。这并不难。
对于DateTime属性,您可以按如下方式执行此操作。只需使用自定义转换器修饰相关属性。
[JsonObject(MemberSerialization.OptIn)]
public class MyClass
{
[JsonProperty(PropertyName = "creation_date")]
[JsonConverter(typeof(UnixDateTimeConverter))]
public DateTime CreationDate { get; set; }
}
JSON.NET提供了大部分管道。只需从基础转换器派生。
public class UnixDateTimeConverter : DateTimeConverterBase
{
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{ ...}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{ ... }
}
您所要做的就是实现ReadJson(反序列化)和WriteJson(序列化)方法。
您可以在此处找到完整的示例:
Writing a custom Json.NET DateTime Converter
对于您的特定问题,您需要更多控制。尝试以下类型的转换器:
public class Contact
{
private List<Address> _addresses = new List<Address>();
public IEnumerable<Address> Addresses { get { return _addresses; }
}
public class ContactConverter : CustomCreationConverter<Contact>
{
public override Contact Create(Type objectType)
{
return new Contact();
}
public override object ReadJson(JsonReader reader, Type objectType, object
existingValue, JsonSerializer serializer)
{
var mappedObj = new Contact();
// Parse JSON data here
// ...
return mappedObj;
}
}
使用上面的自定义转换器,您可以自己解析JSON数据并根据需要编写Contact对象。
我修改了一个我在这里找到的例子:
JSON.NET Custom Converters–A Quick Tour
在这种情况下,您需要在desearilizing时传递自定义转换器。
Contact contact =
JsonConvert.DeserializeObject<Contact>(json, new ContactConverter());
答案 2 :(得分:1)
注意:您可以使用普通的转换器,而不是使用CustomCreationConverter
。例如,我使用这样的东西:
public class SingleToArrayConverter<T> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var items = (IEnumerable<T>)value;
if (value == null || !items.Any())
{
writer.WriteNull();
}
else if (items.Count() == 1)
{
serializer.Serialize(writer, items.ElementAt(0));
}
else
{
serializer.Serialize(writer, items);
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (!CanConvert(objectType))
{
throw new NotSupportedException();
}
if (reader.TokenType == JsonToken.Null)
{
reader.Skip();
return null;
}
else if (reader.TokenType == JsonToken.StartObject)
{
return new T[] { serializer.Deserialize<T>(reader) };
}
else
{
return serializer.Deserialize<T[]>(reader);
}
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(IEnumerable<T>);
}
}