我有下面的界面:
public interface IInterface<out M>
{
M Message { get; }
string Str { get; }
}
及其实现:
public class Implementation<M> : IInterface<M>
{
public M Message;
public string Str;
public Implementation(M message, string str)
{
Message = message;
Str = str;
}
M IInterface<M>.Message => this.Message;
string IInterface<M>.Str => this.Str;
}
下面是一个示例M类:
public class Sample
{
public int X;
}
下面是我从javascript客户端传递的JSON示例:
{ "Message" : { "X": 100 }, "Str" : "abc" }
现在有一些遗留/外部代码(我不能改变),它试图使用JSON反序列化上述JSON对象。Net使用DeserializeObject<IInterface<Sample>>(js_object_string)
.
我如何为这个IInterface
接口写一个JsonConverter处理它的通用参数M
。网上的大多数解决方案只适用于编译时已知的类型。
我尝试了下面的代码(我不完全理解),但是外部代码不认为反序列化的对象是IInterface
。
static class ReflectionHelper
{
public static IInterface<T> Get<T>()
{
var x = JsonConvert.DeserializeObject<T>(str);
IInterface<T> y = new Implementation<T>(x, "xyz");
return y;
}
}
class MyConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(IInterface<>));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var w = Newtonsoft.Json.Linq.JObject.Load(reader);
var x = typeof(ReflectionHelper).GetMethod(nameof(ReflectionHelper.Get)).MakeGenericMethod(objectType.GetGenericArguments()[0]).Invoke(null, new object[] { });
return x;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // otherwise I get a circular dependency error.
serializer.Serialize(writer, value);
}
}
您的MyConverter
可以写如下:
public class MyConverter : JsonConverter
{
public override bool CanConvert(Type objectType) =>
objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(IInterface<>);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (!CanConvert(objectType)) // For safety.
throw new ArgumentException(string.Format("Invalid type {0}", objectType));
var concreteType = typeof(Implementation<>).MakeGenericType(objectType.GetGenericArguments());
return serializer.Deserialize(reader, concreteType);
}
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
}
然后将其添加到Converters
中进行序列化和反序列化,如下所示:
var settings = new JsonSerializerSettings
{
Converters = { new MyConverter() },
};
var root = JsonConvert.DeserializeObject<IInterface<Sample>>(js_object_string, settings);
如果你真的不能改变对DeserializeObject<IInterface<Sample>>(js_object_string)
的调用,您可以将转换器添加到Json。当前线程的全局默认设置如下:
// Set up Json.NET's global default settings to include MyConverter
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
Converters = { new MyConverter() },
};
// And then later, deserialize to IInterface<Sample> via a call that cannot be changed AT ALL:
var root = JsonConvert.DeserializeObject<IInterface<Sample>>(js_object_string);
或者,您可以像这样将MyConverter
直接应用于IInterface<out M>
:
[JsonConverter(typeof(MyConverter))]
public interface IInterface<out M>
{
但是如果你这样做,你必须应用NoConverter
从这个答案如何反序列化泛型接口到泛型具体类型与Json.Net?到Implementation<M>
以避免堆栈溢出异常:
[JsonConverter(typeof(NoConverter))]
public class Implementation<M> : IInterface<M>
{
指出:
通过重写
JsonConverter.CanWrite
并返回false
,我们避免了实现WriteJson()
的需要。在
ReadJson()
中,我们通过从传入的objectType
(某些M
需要为IInterface<M>
)中提取泛型参数来确定要反序列化的具体类型,并使用相同的泛型参数构造一个具体类型Implementation<M>
。Json。. NET支持从参数化构造函数反序列化,如所述:如何在不使用默认构造函数的情况下反序列化?。由于您的
Implementation<M>
具有满足所描述的需求的单个参数化构造函数,因此调用它来正确地反序列化您的具体类。DefaultSettings
适用于整个应用程序中所有线程对JsonConvert
的所有调用,因此您应该确定修改这些设置是否适合您的应用程序。NoConverter
必须应用于Implementation<M>
,因为在没有自己的转换器的情况下,它将从IInterface<out M>
继承MyConverter
,这将在反序列化具体类型时导致对MyConverter.ReadJson()
的递归调用,导致堆栈溢出或循环引用异常。(你可以自己调试来确认)用于生成"default"在不使用转换器的情况下对具体类进行反序列化,参见JSON。Net在使用[JsonConvert()]或时抛出StackOverflowException,在JsonConverter中为某些值类型数组调用默认的JsonSerializer。建议构造一个具体类型的默认实例,然后使用
JsonSerializer.Populate()
填充它的答案将不适合您,因为您的具体类型没有默认构造函数。
DefaultSettings
的Demo提琴,MyConverter
+NoConverter
的Demo提琴。