假设我有以下模型类:
public class Action
{
public enum Type
{
Open,
Close,
Remove,
Delete,
Reverse,
Alert,
ScaleInOut,
Nothing
}
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("active")]
[JsonConverter(typeof(IntToBoolConverter))]
public bool Active { get; set; }
[JsonProperty("type")]
[JsonConverter(typeof(ActionTypeConverter))]
public Type ActionType { get; set; }
[JsonProperty("result")]
[JsonConverter(typeof(ActionResultConverter))]
public ActionResult Result { get; set; }
}
我希望将JSON反序列化到该类中:
{
"name":"test1",
"id":"aa0832f0508bb580ce7f0506132c1c13",
"active":"1",
"type":"open",
"result":{
"property1":"buy",
"property2":"123.123",
"property3":"2016-07-16T23:00:00",
"property4":"768",
"property5":true
}
}
结果对象每次都可以不同(6个模型中的一个),其类型取决于JSON属性type
。
我已经创建了自定义ActionResultConverter
(JsonConverter
类Result
属性Action
以上的result
注释,应该能够创建特定 {{ 1}} object 基于JSON的type
属性中的字符串。
我的问题是我不知道如何从转换器访问该属性,因为只有整个JSON的result
部分传递给JsonReader
。
任何想法或帮助将不胜感激。
谢谢!
答案 0 :(得分:7)
Json.NET不提供在反序列化子对象时访问JSON层次结构中父对象的属性值的方法。可能这是因为根据standard,JSON对象被定义为无序的名称/值对,因此无法保证在子进程之前出现所需的父属性在JSON流中。
因此,您不需要在Type
的转换器中处理ActionResult
属性,而是需要在Action
本身的转换器中执行此操作:
[JsonConverter(typeof(ActionConverter))]
public class Action
{
readonly static Dictionary<Type, System.Type> typeToSystemType;
readonly static Dictionary<System.Type, Type> systemTypeToType;
static Action()
{
typeToSystemType = new Dictionary<Type, System.Type>
{
{ Type.Open, typeof(OpenActionResult) },
};
systemTypeToType = typeToSystemType.ToDictionary(p => p.Value, p => p.Key);
}
public static Type SystemTypeToType(System.Type systemType)
{
return systemTypeToType[systemType];
}
public static System.Type TypeToSystemType(Type type)
{
return typeToSystemType[type];
}
public enum Type
{
Open,
Close,
Remove,
Delete,
Reverse,
Alert,
ScaleInOut,
Nothing
}
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("active")]
[JsonConverter(typeof(IntToBoolConverter))]
public bool Active { get; set; }
[JsonProperty("type")]
[JsonConverter(typeof(ActionTypeConverter))]
public Type ActionType { get; set; }
[JsonProperty("result")]
public ActionResult Result { get; set; }
}
class ActionConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var obj = JObject.Load(reader);
var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType);
var action = existingValue as Action ?? (Action)contract.DefaultCreator();
// Remove the Result property for manual deserialization
var result = obj.GetValue("Result", StringComparison.OrdinalIgnoreCase).RemoveFromLowestPossibleParent();
// Populate the remaining properties.
using (var subReader = obj.CreateReader())
{
serializer.Populate(subReader, action);
}
// Process the Result property
if (result != null)
action.Result = (ActionResult)result.ToObject(Action.TypeToSystemType(action.ActionType));
return action;
}
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public static class JsonExtensions
{
public static JToken RemoveFromLowestPossibleParent(this JToken node)
{
if (node == null)
return null;
var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();
if (contained != null)
contained.Remove();
// Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
if (node.Parent is JProperty)
((JProperty)node.Parent).Value = null;
return node;
}
}
请注意在ReadJson()
内使用JsonSerializer.Populate()
。这会自动填充除Action
以外的Result
的所有属性,从而无需对每个属性进行手动反序列化。
答案 1 :(得分:3)
灵感来自http://json.codeplex.com/discussions/56031:
public sealed class ActionModelConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(ActionModel).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jObject = JObject.Load(reader);
ActionModel actionModel = new ActionModel();
// TODO: Manually populate properties
actionModel.Id = (string)jObject["id"].ToObject<string>();
var type = (ActionModel.Type)jObject["type"].ToObject<ActionModel.Type>();
switch (type)
{
case ActionModel.Type.Open:
var actionResult = jObject["result"].ToObject<ActionOpenResult>(jsonSerializer);
default:
throw new JsonSerializationException($"Unsupported action type: '{type}'");
}
actionModel.Result = actionResult;
return actionModel;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
在编辑器中编码,很抱歉打字错误:)