我需要将jsons反序列化为包含接口类型IExceptionModel属性的类型。我为类的接口指定了映射:
public static class JsonSerialization
{
public static T FromJson<T>(this string obj) => JsonConvert.DeserializeObject<T>(obj, Settings);
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
ContractResolver = new ContractResolver()
};
private class ContractResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
var result = base.CreateContract(objectType);
if (objectType == typeof(IExceptionModel))
{
result.CreatedType = typeof(ExceptionModel);
result.DefaultCreator = () => result.CreatedType.GetConstructor(new Type[0]).Invoke(null);
}
return result;
}
}
}
以下是我的接口和类类型:
public interface IExceptionModel : IModelBase
{
public string Message { get; set; }
public int Index { get; set; }
}
public class ExceptionModel : IExceptionModel
{
public string Message { get ; set ; }
public byte Index { get; set; }
}
以下是要反序列化为的类:
public class Status
{
public IExceptionModel Error { get; set; }
}
当我取一个合适的输入字符串时,比如:
{
"Error" : {
"Message": "Error",
"Index": 404
}
}
并将其馈送到FromJson<状态>方法,我将Error属性设置为null,尽管我相信我已经解决了接口的约定。我还需要做什么才能让它发挥作用?
更新。在准备这个例子时,我把一些细节搞砸了。IExceptionModel Error属性在接口上没有setter。它是在执行时执行的。因此,现在,当我将setter添加到接口时,该属性最终会得到所需的值。如果我擦除它,那么它在反序列化后为null。
因此,问题变成了,我如何告诉Newtonsoft Serializer使用实现的构造函数,使用ITS getter和setter来填充它可以填充的属性,然后将其视为接口实例?
我找到了一个变通方法,为接口属性分配一个内部setter,然后指示:
jsonContract.DefaultCreatorNonPublic = true;
但至少可以说,它让界面看起来很弯曲。
我做了一些更正,这对我来说很有效:
result.CreatedType = typeof(Status);
->result.CreatedType = typeof(ExceptionModel);
public byte Index { get; set; }
->public int Index { get; set; }
我上传了这个在线示例:https://dotnetfiddle.net/ETSJee
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
public interface IModelBase {}
public interface IExceptionModel : IModelBase
{
public string Message { get; set; }
public int Index { get; set; }
}
public class ExceptionModel : IExceptionModel
{
public string Message { get ; set ; }
public int Index { get; set; }
}
public class Status
{
public IExceptionModel Error { get; set; }
}
public static class JsonSerialization
{
public static T FromJson<T>(this string obj)
{
return JsonConvert.DeserializeObject<T>(obj, Settings);
}
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
ContractResolver = new ContractResolver()
};
private class ContractResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
var result = base.CreateContract(objectType);
if (objectType == typeof(IExceptionModel))
{
result.CreatedType = typeof(ExceptionModel);
result.DefaultCreator = () => result.CreatedType.GetConstructor(new Type[0]).Invoke(null);
}
return result;
}
}
}
class Program
{
static void Main(string[] args)
{
var txt = @"
{
'Error' : {
'Message': 'Error',
'Index': 404
}
}
";
var obj = JsonSerialization.FromJson<Status>(txt);
Console.WriteLine(obj.Error.Index);
Console.WriteLine(obj.Error.Message);
}
}
这对我来说是有效的,没有任何合同解决方案
var status = JsonConvert.DeserializeObject<Status>(txt);
public class Status
{
public IExceptionModel Error { get; set; }
[JsonConstructor]
public Status (ExceptionModel error) {
Error=error;
}
public Status() {}
}
如果你需要在很多类中使用它,你可以使用这个代码代替
public class Status
{
[JsonProperty("Error")]
private ExceptionModel _error
{
set { Error = value; }
get { return (ExceptionModel)Error; }
}
[JsonIgnore]
public IExceptionModel Error { get; set; }
}
测试
var status = JsonConvert.DeserializeObject<MyClass>(txt);
Console.WriteLine(status.Error.Index); //404
Console.WriteLine(status.Error.Message); //Error
public class MyClass:Status
{
public string Name {get; set;}
}