我有以下类,它是完全可序列化的:
public class Form {
public IList<IControl> Controls { get; set; }
}
public class ControlA : IControl {}
public class ControlB : IControl {}
它序列化没有 $type
信息,但我有一个自定义JsonConverter
,可以反序列化 IControl
的所有实现:
internal class MyJsonConverter : CustomCreationConverter<IControl> {}
它适用于这样的场景:
[JsonConverter(typeof(MyJsonConverter ))]
public IControl MyControl {get;set;}
但是,我无法将相同的JsonConverterAttribute
应用于我的Form.Controls
媒体资源:
“从JsonReader读取JObject时出错。当前的JsonReader项目不是 一个对象:StartArray。路径'控制',第5行,第15位。“
如何指示反序列化程序在 MyJsonConverter
集合中使用项目<{1}}?
答案 0 :(得分:1)
我不确定您MyJsonConverter
实际上做了什么,但作为一个基本示例,您只需要提供JsonSerializerSettings
并将TypeNameHandling
属性设置为TypeNameHandling.All
这个简单的例子有效。
public interface IControl { }
public class Form
{
public IList<IControl> Controls { get; set; }
}
public class ControlA : IControl { }
public class ControlB : IControl { }
static void Main(string[] args)
{
var form = new Form();
form.Controls = new List<IControl>();
form.Controls.Add(new ControlA());
form.Controls.Add(new ControlB());
var json = JsonConvert.SerializeObject(form, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
var obj = JsonConvert.DeserializeObject<Form>(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
}
修改强>
在澄清没有使用类型处理因此没有$type
属性后,我们必须更有创意并阅读原始jSON
。并以一种特殊的方式构建对象。以下是客户序列化程序的示例。
internal class MyJsonConverter : CustomCreationConverter<IControl>
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jObject = JObject.Load(reader);
var controlType = jObject["CustomProperty"]?.Value<string>();
IControl control = null;
if (!string.IsNullOrWhiteSpace(controlType))
{
switch (controlType.ToLowerInvariant())
{
case "controla":
control = Activator.CreateInstance(typeof(ControlA)) as IControl;
break;
case "controlb":
control = Activator.CreateInstance(typeof(ControlB)) as IControl;
break;
}
}
if (controlType == null)
throw new SerializationException($"Unable to deserialize property. {controlType}");
serializer.Populate(jObject.CreateReader(), control);
return control;
}
public override IControl Create(Type objectType)
{
return null;
}
}
基本上,当我们在IControl
接口中的某个属性(在问题中已经省略)时,我们将手动解析json并获取对属性的引用CustomProperty
如果此属性存在有效字符串值(或者您可以使用任何其他值),我们将手动创建IControl
。
最后,处理反序列化的部分是最后一行serializer.Populate()
完整测试案例:
internal class MyJsonConverter : CustomCreationConverter<IControl>
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jObject = JObject.Load(reader);
var controlType = jObject["CustomProperty"]?.Value<string>();
IControl control = null;
if (!string.IsNullOrWhiteSpace(controlType))
{
switch (controlType.ToLowerInvariant())
{
case "controla":
control = Activator.CreateInstance(typeof(ControlA)) as IControl;
break;
case "controlb":
control = Activator.CreateInstance(typeof(ControlB)) as IControl;
break;
}
}
if (controlType == null)
throw new SerializationException($"Unable to deserialize property. {controlType}");
serializer.Populate(jObject.CreateReader(), control);
return control;
}
public override IControl Create(Type objectType)
{
return null;
}
}
[JsonConverter(typeof(MyJsonConverter))]
public interface IControl
{
string CustomProperty { get; set; }
}
public class Form
{
public IList<IControl> Controls { get; set; }
}
public class ControlA : IControl
{
public string CustomProperty { get; set; } = "ControlA";
}
public class ControlB : IControl
{
public string CustomProperty { get; set; } = "ControlB";
}
static void Main(string[] args)
{
var form = new Form();
form.Controls = new List<IControl>();
form.Controls.Add(new ControlA());
form.Controls.Add(new ControlB());
var json = JsonConvert.SerializeObject(form);
var obj = JsonConvert.DeserializeObject<Form>(json);
}
答案 1 :(得分:1)
您可以使用[JsonProperty(ItemConverterType = typeof(MyJsonConverter))]
将转换器应用于集合中的项目:
public class Form
{
[JsonProperty(ItemConverterType = typeof(MyJsonConverter))]
public IList<IControl> Controls { get; set; }
}