Newtonsoft Json 反序列化为特定类型
Newtonsoft Json deserialization into specific types
我有一个 class 动作和许多其他派生自该动作的特定 classes,例如 SendCoordinates、MakeCall 等。
所以给出这样的 JSON 响应:
{
"action":{
"type":"SendCoordinates",
"data": "41°24'12.2 N 2°10'26.5"
}
}
现在我的问题是关于 Newtonsoft json 库的。实现这个的最佳方法是什么?我是否应该像此处显示的那样为每个 class 创建特定的 JSON 转换器 http://www.newtonsoft.com/json/help/html/DeserializeCustomCreationConverter.htm
或者我应该采用我没有考虑过的完全不同的方法吗?你们能给我留下您对此的看法吗?提前致谢
你可以反序列化为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":{ ... }
}
使用 Newtonsoft.Json 你可以通过非泛型重载反序列化为一个类型 DeserializeObject(string value, type type)
.
这意味着您可以使用 Type
属性 作为反序列化类型的提示。
- 反序列化为基本类型
- 获取实际
Action
对象的类型名称
- 获取类型全名
- 反序列化为派生的操作类型
参见以下示例:
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
字段中指定完整的限定类型名称,您可以使用自定义程序逻辑构造类型的全名(例如,在其前面加上基本命名空间)。
Edit:根据评论,它应该能够反序列化一个 list 动作(派生类型)。因此,我将以下示例附加到我的答案中,您可以在其中看到如何通过执行以下操作来反序列化操作列表:
- 反序列化为通用 JArray
- 为数组中的每个项目确定
Action
的 Type
- 反序列化为特定的派生类型
我还在转换后添加了一个循环来展示如何进一步处理转换后的动作。
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;
}
}
}
}
}
我有一个 class 动作和许多其他派生自该动作的特定 classes,例如 SendCoordinates、MakeCall 等。
所以给出这样的 JSON 响应:
{
"action":{
"type":"SendCoordinates",
"data": "41°24'12.2 N 2°10'26.5"
}
}
现在我的问题是关于 Newtonsoft json 库的。实现这个的最佳方法是什么?我是否应该像此处显示的那样为每个 class 创建特定的 JSON 转换器 http://www.newtonsoft.com/json/help/html/DeserializeCustomCreationConverter.htm
或者我应该采用我没有考虑过的完全不同的方法吗?你们能给我留下您对此的看法吗?提前致谢
你可以反序列化为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":{ ... }
}
使用 Newtonsoft.Json 你可以通过非泛型重载反序列化为一个类型 DeserializeObject(string value, type type)
.
这意味着您可以使用 Type
属性 作为反序列化类型的提示。
- 反序列化为基本类型
- 获取实际
Action
对象的类型名称 - 获取类型全名
- 反序列化为派生的操作类型
参见以下示例:
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
字段中指定完整的限定类型名称,您可以使用自定义程序逻辑构造类型的全名(例如,在其前面加上基本命名空间)。
Edit:根据评论,它应该能够反序列化一个 list 动作(派生类型)。因此,我将以下示例附加到我的答案中,您可以在其中看到如何通过执行以下操作来反序列化操作列表:
- 反序列化为通用 JArray
- 为数组中的每个项目确定
Action
的 - 反序列化为特定的派生类型
Type
我还在转换后添加了一个循环来展示如何进一步处理转换后的动作。
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;
}
}
}
}
}