2015-05-21 77 views
0

我需要從REST服務中使用JSON。對於其中一個字段,該服務有時會爲該值返回一個字符串,但有時會爲該值返回一個字符串數組。將JSON反序列化爲C#:string和string []值

例如:

var jsonArrayResponse = "{ \"id\" : \"abc\", \"relatedIds\" : [ \"def\", \"ghi\", \"jkl\" ] }"; 
var jsonSingleResponse = "{ \"id\" : \"123\", \"relatedIds\" : \"456\" }"; 

我已經使用SingleValueArrayConverter圖案實現的目標類中發現on this post。這裏是全套的代碼來說明我的問題:

class Program 
{ 
    static void Main(string[] args) 
    { 
     // this works fine with the SingleValueArrayConverter 
     var jsonArray = "{ \"id\" : \"abc\", \"relatedIds\" : [ \"def\", \"ghi\", \"jkl\" ] }"; 
     var objArray = (MyObject)JsonConvert.DeserializeObject(jsonArray, typeof(MyObject)); 

     // this fails to parse "456" with Exception message: 
     //  "Unable to cast object of type 'System.Object' to 
     //  type 'System.Collections.Generic.List`1[System.String]'." 
     var jsonSingle = "{ \"id\" : \"123\", \"relatedIds\" : \"456\" }"; 
     var objSingle = (MyObject)JsonConvert.DeserializeObject(jsonSingle, typeof (MyObject)); 
    } 
} 

[DataContract] 
public class MyObject 
{ 
    [DataMember(Name = "id")] 
    public string Id; 

    [DataMember(Name = "relatedIds")] 
    [JsonConverter(typeof(SingleValueArrayConverter<string>))] 
    public List<string> RelatedIds; 
} 

public class SingleValueArrayConverter<T> : JsonConverter 
{ 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     serializer.Serialize(writer, value); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     object retVal = new Object(); 
     if (reader.TokenType == JsonToken.StartObject) 
     { 
      T instance = (T)serializer.Deserialize(reader, typeof(T)); 
      retVal = new List<T>() { instance }; 
     } 
     else if (reader.TokenType == JsonToken.StartArray) 
     { 
      retVal = serializer.Deserialize(reader, objectType); 
     } 
     return retVal; 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return false; 
    } 
} 

我怎樣才能解決這個正確解析兩種不同的JSON的斑點成同一類?

UPDATE:

我修改了SingleValueArrayConverter檢查字符串的情況下(如下文所述),事情開始工作。我使用的轉換器不僅僅是字符串,所以我不得不添加第一個if語句,而不是像建議的那樣修改它)。

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     object retVal = new Object(); 

     if (reader.TokenType == JsonToken.String) 
     { 
      string instance = (string)serializer.Deserialize(reader); 
      retVal = new List<string>() {instance}; 
     } 

     else if (reader.TokenType == JsonToken.StartObject) 
     { 
      T instance = (T)serializer.Deserialize(reader, typeof(T)); 
      retVal = new List<T>() { instance }; 
     } 
     else if (reader.TokenType == JsonToken.StartArray) 
     { 
      retVal = serializer.Deserialize(reader, objectType); 
     } 
     return retVal; 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return false; 
    } 
} 

回答

0

變化JsonToken.StartObject變爲JsonToken.String。如果你在行object retVal = new Object();上放置了一個斷點,你可以在第二次實例化過程中看到reader.TokenTypeJsonToken.String。這是你的代碼唯一的問題。

1

你可以改變這一點:

var jsonSingle = "{ \"id\" : \"123\", \"relatedIds\" : \"456\" }"; 

要這樣:

var jsonSingle = "{ \"id\" : \"123\", \"relatedIds\" : [ \"456\" ] }"; 

...並接受relatedIds有一個或多個項目,因此應該永遠是一個集合。

或者你可能會使RelatedIds通用:

public class MyObject<T> 
{ 
    // .... // 

    public T RelatedIds; 
} 

,你可以使用這樣的:

var objArray = (MyObject<List<string>>)JsonConvert.DeserializeObject(jsonArray, typeof(MyObject<List<string>>)); 

var objSingle = (MyObject<object>)JsonConvert.DeserializeObject(jsonSingle, typeof (MyObject<object>)); 

個人而言,我更喜歡前面的選項,爲簡單起見。

有一件事情你不能做的就是定義爲string突然變成了List<string>在運行時的東西(其實,也許你可以使用dynamic,但最好不要去那裏...)。這在靜態類型語言中是不允許的(儘管在JS或PHP等弱類型語言中是可能的)。

+0

感謝您的快速回復!不幸的是,我無法控制JSON的結構 - 很難找到單個字符串將其包裝在數組大括號中,並且該服務並不能指示我得到的響應的哪種「風味」,所以我將無法使用第二個選項。 – RobK

相關問題