2017-03-11 64 views
0

我有一個Action類,從這個人喜歡SendCoordinates,MakeCall函數等派生出許多其他特定類..Newtonsoft Json的反序列化到特定類型的

所以給出這樣一個JSON響應:

{ 
     "action":{ 
      "type":"SendCoordinates", 
      "data": "41°24'12.2 N 2°10'26.5" 
     } 
} 

現在我的問題是關於Newtonsoft json庫。什麼是實施這個最好的方法?我應該爲每個類創建特定的JSON轉換器,就像他們在這裏展示的那樣:http://www.newtonsoft.com/json/help/html/DeserializeCustomCreationConverter.htm

或者我應該去尋找一種我不考慮的完全不同的方法嗎?你們可以留下你對此的看法嗎?在此先感謝

+0

這不是有效的JSON ... –

+0

是'action'數組還是對象? –

+0

@GeneR這是一個對象,現在它有效,對不起! – Greggz

回答

1

隨着Newtonsoft.Json可以deserialise到通過非通用超載的類型DeserializeObject(string value, type type)

這意味着您可以使用Type屬性作爲要反序列化的類型的提示。

  1. deserialise基地型
  2. 實際 Action對象
  3. 獲取類型類型全名的
  4. 獲取類型名稱
  5. deserialise派生動作類型

請看下面的例子:

using System; 
using Newtonsoft.Json; 

namespace com.example.SO42736347 
{ 
    public class Action 
    { 
     public string Type { get; set; } 
    } 

    public class Action1 : Action 
    { 
     public string Data { get; set; } 
    } 

    public class Program 
    { 

     public const string ACTION1 = @"{ 
      ""Type"" : ""com.example.Json.Action1"", 
      ""Data"" : ""41°24'12.2 N 2°10'26.5"" 
     }"; 

     public static void Main() 
     { 
      var action = JsonConvert.DeserializeObject<Action>(ACTION1); 

      var type = Type.GetType(action.Type); 

      var action1 = (Action1) JsonConvert.DeserializeObject(ACTION1, type); 
     } 

    } 
} 

如果您不想在Type字段中指定完整限定類型名稱,則可以使用自定義程序邏輯(例如,以基名稱空間爲前綴)。

編輯:根據意見,應該能夠deserialise的動作列表(派生類)。因此,我追加下面的例子來我的答案,你可以看到,如何通過執行以下操作來deserialise的操作的列表:在Action

  1. deserialise仿製JArray
  2. 在陣列中的每個項目確定Type
  3. deserialise到特定派生類型

我還添加了循環轉換後以顯示如何進一步處理轉換後的動作。

using System; 
using Newtonsoft.Json; 
using System.Collections.Generic; 
using Newtonsoft.Json.Linq; 

namespace com.example.Json 
{ 
    public class Action 
    { 
     public string Type { get; set; } 
    } 

    public class Action1 : Action 
    { 
     public string Data { get; set; } 
    } 

    public class Action2 : Action 
    { 
     public string SomeProperty { get; set; } 
    } 

    public class Program 
    { 

     public const string ACTION1 = @"{ 
     ""Type"" : ""com.example.Json.Action1"", 
      ""Data"" : ""41°24'12.2 N 2°10'26.5"" 
     }"; 

     public const string ACTION2 = @"{ 
     ""Type"" : ""com.example.Json.Action2"", 
      ""SomeProperty"" : ""arbitrary-value"" 
     }"; 

     public const string ACTIONS = 
      "[" + 
      ACTION1 + 
      "," + 
      ACTION2 + 
      "]" ; 

     public static void Main() 
     { 

      var actions = new List<Action>(); 

      JArray jArray = JArray.Parse(ACTIONS); 
      foreach(var item in jArray) 
      { 
       var json = JsonConvert.SerializeObject(item); 
       var baseAction = JsonConvert.DeserializeObject<Action>(json); 
       var type = Type.GetType(baseAction.Type); 
       var action = (Action) JsonConvert.DeserializeObject(json, type); 
       actions.Add(action); 
      } 

      // now that we have converted all array items into specific derived action objects 
      // we can start processing them anyway we want 
      // keep in mind that you have to check the runtime type in order to find out what 
      // specific kind of action we have 

      // eg. 
      foreach(var action in actions) 
      { 
       switch(action.Type) 
       { 
        case "com.example.Json.Action1": 
         // do something 
         Console.WriteLine("found com.example.Json.Action1"); 
         Console.WriteLine((action as Action1).Data); 
         break; 
        case "com.example.Json.Action2": 
         // do something 
         Console.WriteLine("found com.example.Json.Action2"); 
         Console.WriteLine((action as Action2).SomeProperty); 
         break; 
        default: 
         // do something 
         Console.WriteLine("found something else"); 
         break; 
       } 
      } 

     } 

    } 
} 
+0

謝謝你的迴應。所以這必須是兩步反序列化?鑑於你的例子,我希望「var action」已經是Action1類型。有沒有辦法做到這一點 ? – Greggz

+0

你當然可以通過文本解析(或正則表達式)json文本來找出'type'屬性。但是這種方法更安全,更容易排除故障(增加了一些錯誤檢查功能)。 (Action1)JsonConvert.DeserializeObject(ACTION1,Type.GetType(JsonConvert.DeserializeObject (ACTION1).Type));'如果你真的想避免聲明另一個變量,你可以使它更緊湊像這樣: ,但這並沒有使它更具可讀性。 是否有任何不使用兩個變量的原因? –

+0

是的,導致我的主要JSON響應將是一個操作數組,我將根據該信息填充視圖,如下所示:var內容= JsonConvert.DeserializeObject(Actions); '那麼有沒有辦法給JsonConvert提供他需要的工具來自動完成特定的轉換? – Greggz

0

你可以把它反序列化到SomeObject

public class SomeObject 
{ 
    public SomeAction Action { get; set; } 
    public OtherAction Call { get; set; } 
} 
public class SomeAction 
{ 
    public string Type { get; set; } 
    public string Data { get; set; } 
} 
public class OtherAction { ... } 

可能json反序列化:

{ 
    "action":{ "type":"SendCoordinates", "data": "41°24'12.2 N 2°10'26.5" } 
} 

或:

{ 
    "call":{ ... } 
} 
+0

public SomeAction Action?這對我來說沒有意義。行動是我的基礎課。該領域只是公共行動? – Greggz

+0

我的問題是如何決定應該將哪種類型轉換爲 – Greggz

+0

然後你的'json'應該看起來像'{「type」:「SendCoordinates」,「data」:「41°24'12.2 N 2°10 '26 .5「}',那麼你可以將它反序列化爲你的'Action class' –

相關問題