我的问题是,我需要反序列化JSON到一个类型,该类型又包含接口类型对象,因此需要指示Json.NET如何转换该接口类型,但我不直接控制Newtonsoft.Json.Deserializer
。反序列化由框架代码间接处理,即由HttpContent.ReadAsAsync<T>处理。如何指示Json.NET将接口类型转换为具体类型而无需访问序列化程序?
如何指定从接口类型到具体类型的转换,但无法直接向JsonSerializer.Converters
添加转换器?如果我在接口定义上使用[JsonConverter]
属性,转换器也会被调用以实现接口(即,我要转换的具体类型)。
在下面的代码示出了尝试将反序列化相同的JSON首先将Parent2
类,然后将Parent1
类,指示Json.NET经由JsonConverterAttribute
的IChild1
接口类型转换为Child1
具体类型C#控制台程序。由于我将ChildConverter
直接添加到serializer.Converters
,而反序列化到Parent1
会导致堆栈溢出异常,因为即使对Child1
类型也调用ChildConverter.Deserialize
,因此将其反序列化为Parent2
。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.IO;
namespace TestConsole
{
[JsonConverter(typeof(ChildConverter))]
interface IChild1
{
string Name { get; set; }
}
class Child1 : IChild1
{
public string Name { get; set; }
}
class Parent1
{
public IEnumerable<IChild1> Children { get; set; }
}
interface IChild2
{
string Name { get; set; }
}
class Child2 : IChild2
{
public string Name { get; set; }
}
class Parent2
{
public IEnumerable<IChild2> Children { get; set; }
}
class ChildConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(IChild1) || objectType == typeof(IChild2);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (objectType == typeof(IChild1))
return serializer.Deserialize<Child1>(reader);
return serializer.Deserialize<Child2>(reader);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
class Program
{
static void Main(string[] args)
{
var json = "{'Children': [{'Name': 'Child1'}, {'Name': 'Child2'}]}";
var serializer = new JsonSerializer();
serializer.Converters.Add(new ChildConverter());
var obj = serializer.Deserialize(new StringReader(json), typeof(Parent2));
serializer = new JsonSerializer();
obj = serializer.Deserialize(new StringReader(json), typeof(Parent1));
}
}
}