gpt4 book ai didi

c# - 如何根据另一个 JSON 属性有条件地反序列化 JSON 对象?

转载 作者:太空狗 更新时间:2023-10-30 00:18:21 25 4
gpt4 key购买 nike

假设我有以下模型类:

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(Action 类的 Result 属性上方的 JsonConverter 注释)应该能够根据 JSON 的 type 属性中的字符串创建特定的 result object

我的问题是我不知道如何从转换器访问该属性,因为只有整个 JSON 的 result 部分被传递给 JsonReader

任何想法或帮助将不胜感激。

谢谢!

最佳答案

Json.NET 不提供在反序列化子对象时访问 JSON 层次结构中父对象的属性值的方法。这可能是因为根据 standard,JSON 对象被定义为无序的名称/值对集。 ,因此不能保证所需的父属性出现在 JSON 流中的子属性之前。

因此,您需要在 Action 的转换器中处理 Type 属性,而不是在 ActionResult 的转换器中处理本身:

[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;
}
}

注意 JsonSerializer.Populate() 的使用在 ReadJson() 中。这会自动填充 Action 的所有属性,而不是 Result,避免对每个属性进行手动反序列化。

关于c# - 如何根据另一个 JSON 属性有条件地反序列化 JSON 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38357864/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com