我正在反序列化一个复杂的json结构,如下所示,其中“events”下的“id”代表
"events": [
{
"id": 1,
"actions": [
{
"id": 8,
"values": {
"obj_id":160,
"url": "https://www.myurl.com/"
}
},
{
"id":15,
"values":{
"obj_id":182,
"scale":200
}
}
]
}
]
我有一个抽象的 ActionBase 类和多个派生类,不同的值基于不同的操作 id。
public class Events
{
public int id;
public ActionsHolder[] actions;
}
[JsonConverter(typeof(BaseConverter))]
public class ActionsHolder
{
public int id { get; set; } = -1;
public ActionBase values { get; set; }
}
public abstract class ActionBase : ActionsHolder
{
public int obj_id { get; set; }
}
public class OpenURLAction : ActionBase
{
//Action id 8 = Open URL
public string url { get; set; }
}
public class ScaleAction : ActionBase
{
//Action id 15 = Scale
public float scale { get; set; } = 1;
}
public class BaseSpecifiedConcreteClassConverter : DefaultContractResolver
{
protected override JsonConverter ResolveContractConverter(Type objectType)
{
if (typeof(ActionsHolder).IsAssignableFrom(objectType) && !objectType.IsAbstract)
{
return null;
}
return base.ResolveContractConverter(objectType);
}
}
public class BaseConverter : JsonConverter
{
static JsonSerializerSettings SpecifiedSubclassConversion = new JsonSerializerSettings()
{
ContractResolver = new BaseSpecifiedConcreteClassConverter() ,
TypeNameHandling = TypeNameHandling.All
};
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(ActionsHolder));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject joAction = JObject.Load(reader);
JObject joValues = (JObject)joAction["values"];
switch (joAction["id"].Value<int>())
{
case 8:
return new ActionsHolder
{
id = joAction["id"].Value<int>(),
values = JsonConvert.DeserializeObject<OpenURLAction>(joValues.ToString(), SpecifiedSubclassConversion)
};
case 15:
return new ActionsHolder
{
id = joAction["id"].Value<int>(),
values = JsonConvert.DeserializeObject<ScaleAction>(joValues.ToString(), SpecifiedSubclassConversion)
};
default:
return null;
}
throw new NotImplementedException();
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();returns false
}
}
但是,这不起作用。 我的自定义转换器如何仅反序列化其他人的操作属性和默认转换器... 有人可以帮忙吗?
我会修改您的类型层次结构和
JsonConverter
的设计,如下所示:
public class Root // Not shown in your question
{
public List<Event> events { get; set; } = new();
}
public class Event
{
public int id { get; set; } // Does this have a fixed value of 1?
public List<ActionHolder> actions { get; set; } = new();
}
[JsonConverter(typeof(ActionHolderConverter))]
public class ActionHolder
{
public int id => (int)(values?.id ?? ActionValueType.None);
public ActionValueBase values { get; set; }
}
public enum ActionValueType
{
None = -1,
OpenURL = 8,
Scale = 15,
}
public abstract class ActionValueBase
{
[JsonIgnore] public abstract ActionValueType id { get; }
public int obj_id { get; set; }
}
public class OpenURLActionValue : ActionValueBase
{
public override ActionValueType id => ActionValueType.OpenURL;
public string url { get; set; }
}
public class ScaleActionValue : ActionValueBase
{
public override ActionValueType id => ActionValueType.Scale;
public float scale { get; set; } = 1;
}
并重写你的
JsonConverter
如下:
class ActionHolderConverter : JsonConverter<ActionHolder>
{
public override ActionHolder ReadJson(JsonReader reader, Type objectType, ActionHolder existingValue, bool hasExistingValue, JsonSerializer serializer)
{
JObject joAction = JObject.Load(reader);
var values = (ActionValueType)joAction[nameof(ActionHolder.id)].Value<int>() switch
{
ActionValueType.Scale => joAction[nameof(ActionHolder.values)]?.ToObject<ScaleActionValue>(serializer),
ActionValueType.OpenURL => joAction[nameof(ActionHolder.values)]?.ToObject<OpenURLActionValue>(serializer),
ActionValueType.None => (ActionValueBase)null,
var t => throw new JsonSerializationException($"Unknown ActionValueTypes {t}"),
};
var holder = existingValue ?? new ActionHolder();
holder.values = values;
return holder;
}
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, ActionHolder value, JsonSerializer serializer) => throw new NotImplementedException();
}
要点:
在您的设计中,
ActionBase
继承自ActionHolder
,但这似乎是一个错误。在 JSON 中,具有两个值 events[*].actions[*]
和 "id"
的 "values"
对象与具有 "values"
属性和其他属性的嵌套 "obj_id"
对象之间有明显的区别。由于这两者之间没有共同的属性,因此使用 ActionBase
作为两者的基类是没有意义的。
我引入了一个
enum
对应于id
的可能值。
由于
ActionHolder.id
完全由值的类型定义,因此我将其设置为只读,并根据 ActionValueBase
的虚拟只读属性确定,而该属性又由类型确定。
如果您有机会想要添加到
events
和 actions
集合中,我建议使用可调整大小的 List<T>
列表,而不是固定长度的数组。
演示小提琴这里。