c# – JSON.NET:如何反序列化基於parent(holder)物件值的介面屬性?
我有這樣的課
class Holder { public int ObjType { get; set; } public List<Base> Objects { get; set; } } abstract class Base { // ... doesn't matter } class DerivedType1 : Base { // ... doesn't matter } class DerivedType2 : Base { // ... doesn't matter }
使用WebAPI我想要接收物件持有者並正確反序列化它.基於ObjType值,我需要將Objects屬性反序列化為List<DerivedType1> (ObjType == 1)或List<DerivedType2> (ObjType == 2).
目前我搜索了SO和網際網路的最佳方法,但是我發現最好的是這個答案ofollow,noindex" target="_blank">http://stackoverflow.com/a/8031283/1038496 .這個解決方案的問題是,它鬆動父物件的上下文,所以我找不到ObjType的值.好的,我可以通過為Holder建立自定義的JsonConverter並重寫ObjType值來解決這個問題,但是我仍然害怕這一行
serializer.Populate(jObject.CreateReader(), target);
正如這個答案所說的那樣
The new JsonReader created in the ReadJson method does not inherit any of the original reader’s configuration values (Culture, DateParseHandling, DateTimeZoneHandling, FloatParseHandling, etc…). These values should be copied over before using the new JsonReader in serializer.Populate().
這對我來說是個問題,我自己複製這些價值觀對我來說看起來並不乾淨(如果我想念某件事情呢?)
所以問題是:有沒有更好的方法我錯過了反序列化抽象物件屬性基於父屬性值?
你在正確的軌道上.您確實需要為您的Holder類實現一個自定義JsonConverter來處理這種情況,就像您所建議的那樣.但是,不要擔心,可以以這樣的方式編寫轉換器,即可以使用傳遞給轉換器的原始讀取器和序列器例項,而無需將設定複製到新的例項.這是我如何寫:
class HolderConverter : JsonConverter { public override bool CanConvert(Type objectType) { return (objectType == typeof(Holder)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject jo = JObject.Load(reader); Holder holder = new Holder(); holder.ObjType = (int)jo["ObjType"]; holder.Objects = new List<Base>(); foreach (JObject obj in jo["Objects"]) { if (holder.ObjType == 1) holder.Objects.Add(obj.ToObject<DerivedType1>(serializer)); else holder.Objects.Add(obj.ToObject<DerivedType2>(serializer)); } return holder; } public override bool CanWrite { get { return false; } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } }
這是一個快速演示:
class Program { static void Main(string[] args) { string json = @" [ { ""ObjType"" : 1, ""Objects"" : [ { ""Id"" : 1, ""Foo"" : ""One"" }, { ""Id"" : 2, ""Foo"" : ""Two"" }, ] }, { ""ObjType"" : 2, ""Objects"" : [ { ""Id"" : 3, ""Bar"" : ""Three"" }, { ""Id"" : 4, ""Bar"" : ""Four"" }, ] }, ]"; List<Holder> list = JsonConvert.DeserializeObject<List<Holder>>(json); foreach (Holder holder in list) { if (holder.ObjType == 1) { foreach (DerivedType1 obj in holder.Objects) { Console.WriteLine("Id: " + obj.Id + "Foo: " + obj.Foo); } } else { foreach (DerivedType2 obj in holder.Objects) { Console.WriteLine("Id: " + obj.Id + "Bar: " + obj.Bar); } } } } } [JsonConverter(typeof(HolderConverter))] class Holder { public int ObjType { get; set; } public List<Base> Objects { get; set; } } abstract class Base { public int Id { get; set; } } class DerivedType1 : Base { public string Foo { get; set; } } class DerivedType2 : Base { public string Bar { get; set; } }
輸出:
Id: 1Foo: One Id: 2Foo: Two Id: 3Bar: Three Id: 4Bar: Four
程式碼日誌版權宣告:
翻譯自:http://stackoverflow.com/questions/22537233/json-net-how-to-deserialize-interface-property-based-on-parent-holder-object