2011-11-23 10 views
35

का उपयोग कर मेरे पास एक JSON-array है जिसमें विभिन्न गुणों के साथ विभिन्न प्रकार के ऑब्जेक्ट हैं। गुणों में से एक को "टाइप" कहा जाता है और सरणी आइटम के प्रकार को निर्धारित करता है।कोपरिएन्टिस में हेटरोजेनस JSON सरणी deserializing सूची <> JSON.NET

[{ 
     type : "comment", 
     text : "xxxx" 
    }, { 
     type : "code", 
     tokens : [{ 
       type : "ref", 
       data : "m" 
      }, { 
       type : "operator", 
       data : "e" 
      } 
     ] 
    }, { 
     type : "for", 
     boundLocal : { 
      type : "local", 
      name : "i", 
      kind : "Number" 
     }, 
     upperBound : { 
      type : "ref", 
      tokens : [{ 
        type : "operator", 
        data : "3" 
       }, { 
        type : "operator", 
        data : "0" 
       } 
      ] 
     }, 
     body : [{ 
       type : "code", 
       tokens : [{ 
         type : "ref", 
         data : "x" 
        } 
       ] 
      }, { 
       type : "code", 
       tokens : [{ 
         type : "ref", 
         data : "y" 
        } 
       } 
       ] 
     ] 
    ] 

मेरी नेट कार्यान्वयन के लिए उन वस्तुओं मैं कक्षाओं का एक सेट को परिभाषित नक़्शा बनाने के लिए: एक आधार वर्ग और कई बच्चे कक्षाओं (एक जटिल पदानुक्रम के साथ, 4 "पीढ़ियों" होने) यहाँ अपने डेटा का एक उदाहरण है । यहां केवल इन कक्षाओं का एक छोटा सा उदाहरण है:

public abstract class TExpression 
{ 
    [JsonProperty("type")] 
    public string Type { get; set; } 
} 

public class TComment : TExpression 
{ 
    [JsonProperty("text")] 
    public string Text { get; set; } 
} 

public class TTokenSequence : TExpression 
{ 
    [JsonProperty("tokens")] 
    public List<TToken> Tokens { get; set; } 
} 

क्या मैं तक पहुँचना चाहते हैं एक covariant सामान्य सूची में इस सरणी deserialize करने में सक्षम होना है, की घोषणा की है:

List<TExpression> myexpressions = JsonConvert.DeserializeObject<List<TExpression>>(aststring); 

इस सूची में शामिल करना चाहिए उचित बच्चे कक्षाएं, TExpression से इनहेरिट इसलिए मैं अपने कोड में बाद में निम्न कोड का उपयोग कर सकते के उदाहरण:

foreach(TExpression t in myexpressions) 
{ 
    if (t is TComment) dosomething; 
    if (t is TTokenSequence) dosomethingelse; 
} 

मैं इसे कैसे JSON.NET का उपयोग कर पहुँच सकते हैं?

+0

की संभावित डुप्लिकेट https://stackoverflow.com/questions/35182949/deserialize-json-string-depending- ऑन-टाइप/44650012 – manuc66

उत्तर

44

कस्टमक्रिएशन कनवर्टर का उपयोग करके यहां एक उदाहरण दिया गया है।

public class JsonItemConverter : Newtonsoft.Json.Converters.CustomCreationConverter<Item> 
{ 
    public override Item Create(Type objectType) 
    { 
     throw new NotImplementedException(); 
    } 

    public Item Create(Type objectType, JObject jObject) 
    { 
     var type = (string)jObject.Property("valueType"); 
     switch (type) 
     { 
      case "int": 
       return new IntItem(); 
      case "string": 
       return new StringItem(); 
     } 

     throw new ApplicationException(String.Format("The given vehicle type {0} is not supported!", type)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     // Load JObject from stream 
     JObject jObject = JObject.Load(reader); 

     // Create target object based on JObject 
     var target = Create(objectType, jObject); 

     // Populate the object properties 
     serializer.Populate(jObject.CreateReader(), target); 

     return target; 
    } 
} 

public abstract class Item 
{ 
    public string ValueType { get; set; } 

    [JsonProperty("valueTypeId")] 
    public int ValueTypeId { get; set; } 

    [JsonProperty("name")] 
    public string Name { get; set; } 

    public new virtual string ToString() { return "Base object, we dont' want base created ValueType=" + this.ValueType + "; " + "name: " + Name; } 
} 

public class StringItem : Item 
{ 
    [JsonProperty("value")] 
    public string Value { get; set; } 

    [JsonProperty("numberChars")] 
    public int NumberCharacters { get; set; } 

    public override string ToString() { return "StringItem object ValueType=" + this.ValueType + ", Value=" + this.Value + "; " + "Num Chars= " + NumberCharacters; } 

} 

public class IntItem : Item 
{ 
    [JsonProperty("value")] 
    public int Value { get; set; } 

    public override string ToString() { return "IntItem object ValueType=" + this.ValueType + ", Value=" + this.Value; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     // json string 
     var json = "[{\"value\":5,\"valueType\":\"int\",\"valueTypeId\":1,\"name\":\"numberOfDups\"},{\"value\":\"some thing\",\"valueType\":\"string\",\"valueTypeId\":1,\"name\":\"a\",\"numberChars\":11},{\"value\":2,\"valueType\":\"int\",\"valueTypeId\":2,\"name\":\"b\"}]"; 

     // The above is deserialized into a list of Items, instead of a hetrogenous list of 
     // IntItem and StringItem 
     var result = JsonConvert.DeserializeObject<List<Item>>(json, new JsonItemConverter()); 

     foreach (var r in result) 
     { 
      // r is an instance of Item not StringItem or IntItem 
      Console.WriteLine("got " + r.ToString()); 
     } 
    } 
} 
+0

अमूर्त 'बनाएं' विधि के कारणों में 'NotImplementedException' को फेंक नहीं देगा समस्याओं का कारण बनता है? – GregRos

0

यह भी एक कथात्मक तरह से JsonSubTypes साथ इसे लागू किया जा सकता है:

[JsonConverter(typeof(JsonSubtypes), "valueType")] 
[JsonSubtypes.KnownSubType(typeof(IntItem), "int")] 
[JsonSubtypes.KnownSubType(typeof(StringItem), "string")] 
public abstract class Item 
{ 
    public string ValueType { get; set; } 

    [JsonProperty("valueTypeId")] 
    public int ValueTypeId { get; set; } 

    [JsonProperty("name")] 
    public string Name { get; set; } 

    public override string ToString() 
    { 
     return "Base object, we dont' want base created ValueType=" + this.ValueType + "; " + "name: " + Name; 
    } 
} 

public class StringItem : Item 
{ 
    [JsonProperty("value")] 
    public string Value { get; set; } 

    [JsonProperty("numberChars")] 
    public int NumberCharacters { get; set; } 

    public override string ToString() 
    { 
     return "StringItem object ValueType=" + this.ValueType + ", Value=" + this.Value + "; " + 
       "Num Chars= " + NumberCharacters; 
    } 
} 

public class IntItem : Item 
{ 
    [JsonProperty("value")] 
    public int Value { get; set; } 

    public override string ToString() 
    { 
     return "IntItem object ValueType=" + this.ValueType + ", Value=" + this.Value; 
    } 
} 

[TestMethod] 
public void Demo() 
{ 
    // json string 
    var json = 
     "[{\"value\":5,\"valueType\":\"int\",\"valueTypeId\":1,\"name\":\"numberOfDups\"}," + 
     "{\"value\":\"some thing\",\"valueType\":\"string\",\"valueTypeId\":1,\"name\":\"a\",\"numberChars\":11}," + 
     "{\"value\":2,\"valueType\":\"int\",\"valueTypeId\":2,\"name\":\"b\"}]"; 

    var result = JsonConvert.DeserializeObject<List<Item>>(json); 

    Assert.AreEqual("IntItem object ValueType=int, Value=5", result[0].ToString()); 
    Assert.AreEqual("StringItem object ValueType=string, Value=some thing; Num Chars= 11", result[1].ToString()); 
    Assert.AreEqual("IntItem object ValueType=int, Value=2", result[2].ToString()); 
}