Json.Net反序列化和序列化具有更改名称的属性
本文关键字:属性 反序列化 Net 序列化 Json | 更新日期: 2023-09-27 18:14:06
我正在与第三方集成,他们返回的JSON让我陷入了一个循环。我想把它反序列化成一个类。但是大多数属性名是可以改变的。
{
"transaction_id":1,
"status":"Reviewing",
"changelog":{
"2016-Mar-15 10:28 AM":{
"status":{
"from":"Approved",
"to":"Reviewing"
},
"total":{
"from":123.45,
"to":246.90
},
"shipping_address_1":{
"from":"321 S Main St.",
"to":"8355 NW 74th St"
},
"shipping_city":{
"from":"New York",
"to":"Medley"
},
"shipping_state":{
"from":"NY",
"to":"FL"
},
"shipping_postal":{
"from":"10002",
"to":"33166"
}
}
}
}
我想有一个类似的类。
public class TransactionChangeLog
{
[JsonProperty(PropertyName = "transaction_id")]
public int TransactionId { get; set; }
[JsonProperty(PropertyName = "status")]
public TransactionStatus Status { get; set; }
[JsonProperty(PropertyName = "changelog")]
public ICollection<TransactionChange> Changelog { get; set; }
}
public class TransactionChange
{
// ?? What to do with this.
public DateTime ChangeDate { get; set; }
// ?? What to do with this.
public string Field { get; set; }
public string From { get; set; }
public string To { get; set; }
}
您可以采用几种方法来处理此问题。第一种(也是最简单的)方法是在TransactionChangeLog
类中使用嵌套字典:
public class TransactionChangeLog
{
[JsonProperty(PropertyName = "transaction_id")]
public int TransactionId { get; set; }
[JsonProperty(PropertyName = "status")]
public TransactionStatus Status { get; set; }
[JsonProperty(PropertyName = "changelog")]
public Dictionary<DateTime, Dictionary<string, TransactionChange>> Changelog { get; set; }
}
public class TransactionChange
{
public string From { get; set; }
public string To { get; set; }
}
你可以像这样反序列化和转储数据:
TransactionChangeLog changeLog = JsonConvert.DeserializeObject<TransactionChangeLog>(json);
Console.WriteLine("TransactionId: " + changeLog.TransactionId);
Console.WriteLine("TransactionStatus: " + changeLog.Status);
foreach (var dateKvp in changeLog.Changelog)
{
Console.WriteLine(dateKvp.Key); // change date
foreach (var fieldKvp in dateKvp.Value)
{
Console.WriteLine(" changed " + fieldKvp.Key + " from '" + fieldKvp.Value.From + "' to '" + fieldKvp.Value.To + "'");
}
}
小提琴:https://dotnetfiddle.net/vXNcKi
虽然上面的方法可以工作,但是使用嵌套字典会有点尴尬。另一种方法是使用JsonConverter
来处理不断变化的JSON的反序列化。这将允许您使用在问题中定义的类。您可以这样编写转换器:
public class ChangeLogConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ICollection<TransactionChange>);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
List<TransactionChange> changes = new List<TransactionChange>();
JObject changelog = JObject.Load(reader);
foreach (JProperty dateProp in changelog.Children<JProperty>())
{
DateTime changeDate = DateTime.ParseExact(dateProp.Name, "yyyy-MMM-dd hh:mm tt", CultureInfo.InvariantCulture);
foreach (JProperty fieldProp in dateProp.Value.Children<JProperty>())
{
TransactionChange change = new TransactionChange();
change.ChangeDate = changeDate;
change.Field = fieldProp.Name;
change.From = (string)fieldProp.Value["from"];
change.To = (string)fieldProp.Value["to"];
changes.Add(change);
}
}
return changes;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
要使用转换器,在TransactionChangeLog
类的Changelog
属性中添加[JsonConverter]
属性:
public class TransactionChangeLog
{
[JsonProperty(PropertyName = "transaction_id")]
public int TransactionId { get; set; }
[JsonProperty(PropertyName = "status")]
public TransactionStatus Status { get; set; }
[JsonProperty(PropertyName = "changelog")]
[JsonConverter(typeof(ChangeLogConverter))]
public ICollection<TransactionChange> Changelog { get; set; }
}
然后你可以像平常那样反序列化和转储数据:
TransactionChangeLog changeLog = JsonConvert.DeserializeObject<TransactionChangeLog>(json);
Console.WriteLine("TransactionId: " + changeLog.TransactionId);
Console.WriteLine("TransactionStatus: " + changeLog.Status);
foreach (TransactionChange change in changeLog.Changelog)
{
Console.WriteLine(change.ChangeDate + " - changed " + change.Field + " from '" + change.From + "' to '" + change.To + "'");
}
小提琴:https://dotnetfiddle.net/1d3pUa
如果我理解正确的话,changelog
的内容可能会有所不同,并且您在编译时不知道可能的属性名称。
如果是这种情况,您需要反序列化到非静态类型的东西,例如JObject
,它可以用于之后对数据进行linq风格的查询。