2017-03-11 62 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' –

相关问题