在JSON.NET中反序列化IList <Interface>

The*_*hud 3 c# json json.net deserialization

我有一些要反序列化的json。将序列反序列化很容易,但是我正在使用接口,这就是我需要反序列化的结果:

因此,让我们从一些JSON开始:

[{"TimeGenerated":"2017-05-30T19:21:06.5331472+10:00","OuterValue":1.08,"Identifier":{"IdentifierName":"BLA","IdentifierNumber":1},"Locale":{"LocaleName":"LOCALE NAME","LocaleType":1,"LocaleNumber":1,"StartTime":"2017-05-30T19:20:00+10:00"},"InnerValue":1.08,"InnerType":0,"InnerId":"InnerI","Type":"MyType","Id":"11111"}]
Run Code Online (Sandbox Code Playgroud)

这是在服务器端进行序列化的数据(当然没有问题),其对象类型为:

IList<IRootObject>
Run Code Online (Sandbox Code Playgroud)

如此有效,我想反序列化为:

IList<IRootObject> MyDeserialisedObject = JsonConvert.Deserialise<IList<IRootObject>>(JsonString);
Run Code Online (Sandbox Code Playgroud)

显然,这里的泡菜是以下的旧界面/抽象类型错误:

'Could not create an instance of type BLA. Type is an interface or abstract class and cannot be instantiated'
Run Code Online (Sandbox Code Playgroud)

很好,我创建了一些自定义转换器,并进行了如下装饰:

类是:

    [JsonObject(MemberSerialization.OptIn)]
    public class Identifier
    {
        [JsonProperty]
        public string IdentifierName { get; set; }
        [JsonProperty]
        public int IdentifierNumber { get; set; }
    }
    [JsonObject(MemberSerialization.OptIn)]
    public class Locale
    {
        [JsonProperty]
        public string LocaleName { get; set; }
        [JsonProperty]            
        public int LocaleType { get; set; }
        [JsonProperty]            
        public int LocaleNumber { get; set; }
        [JsonProperty]
        public string StartTime { get; set; }
    }

    [JsonObject(MemberSerialization.OptIn)]
    public class RootObject:IRootObject
    {
       [JsonProperty]
       public string TimeGenerated { get; set; }
       [JsonProperty]        
       public double OuterValue { get; set; }
       [JsonProperty] 
       [JsonConverter(typeof(ConcreteConverter<Identifier>))]
       public IIdentifier Identifier { get; set; }
       [JsonProperty]
       [JsonConverter(typeof(ConcreteConverter<Locale>))]
       public ILocale Locale { get; set; }
       [JsonProperty]
       public double InnerValue { get; set; }
       [JsonProperty]
       public int InnerType { get; set; }
       [JsonProperty]
       public string InnerId { get; set; }
       [JsonProperty]
       public string Type { get; set; }
       [JsonProperty]
       public string Id { get; set; }
    }
Run Code Online (Sandbox Code Playgroud)

界面是:

public interface IRootObject
{
    string TimeGenerated { get; set; }
    double OuterValue { get; set; }
    Identifier Identifier { get; set; }
    Locale Locale { get; set; }
    double InnerValue { get; set; }
    int InnerType { get; set; }
    string InnerId { get; set; }
    string Type { get; set; }
    string Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

具体转换器如下:

public class ConcreteConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    try
    {
        var s = serializer.Deserialize<T>(reader);
        return s;
    }
    catch (Exception ex)
    {
        return null;
    }
    // return serializer.Deserialize<T>(reader);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    serializer.Serialize(writer, value);
}
Run Code Online (Sandbox Code Playgroud)

}

我也有一个列表转换器,我已经制作了一个列表转换器(尽管这是一个未使用的列表,但是这里需要JIC):

public class ConcreteListConverter<TInterface, TImplementation> : JsonConverter where TImplementation : TInterface
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    if (existingValue == null)
        return null;

    var res = serializer.Deserialize<List<TImplementation>>(reader);
    return res.ConvertAll(x => (TInterface)x);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    serializer.Serialize(writer, value);

}
Run Code Online (Sandbox Code Playgroud)

}

因此,问题是:

当我跑步时:

IList<IRootObject> MyDeserialisedObject = JsonConvert.Deserialise<IList<IRootObject>>(JsonString);
Run Code Online (Sandbox Code Playgroud)

我总是得到一个空值。

当我在我的ConcreteConverter CanConvert / ReadJson / WriteJson方法上设置断点时,它们就永远不会被击中。

我想念的是什么,以及如何获得以下优势:

IList<IRootObject> MyDeserialisedObject = JsonConvert.Deserialise<IList<IRootObject>>(JsonString);
Run Code Online (Sandbox Code Playgroud)

正常工作。

我必须注意,我不想只是在它将ASSEMBLYNAME.TYPE等添加到json中从而使其膨胀的typnamehandling.objects(我认为是这样)。只需假设上面的json是我们必须使用的,上面表示的类及其接口就是必须反序列化的对象。

问候,

丘德

PS-我已经更改了类名/属性等,而与我正在做的实际操作不同。因此,如果他们出了错,我深表歉意。但希望大多数都可以,并且理解了重点/最终目标:)

Cod*_*shi 5

问题

您无法创建接口实例,.NET不允许这样做。你不能做这个:

var items = new IList<int>(); // Not allowed
Run Code Online (Sandbox Code Playgroud)

您的错误清楚地表明:

无法创建BLA类型的实例。类型是接口或抽象类,无法实例化”

解决方案

List将其反序列化为type,但将其分配为type IList。请注意,右侧的类型不是下面代码中的接口,除非在转换阶段。

IList<IRootObject> MyDeserialisedObject = 
            JsonConvert.DeserializeObject<List<RootObject>>(File.ReadAllText(JsonString))
            .Cast<IRootObject>().ToList();
Run Code Online (Sandbox Code Playgroud)

更多的困惑

您可能会问“为什么需要投射”,为什么我不能这样做呢?

IList<IRootObject> MyDeserialisedObject = 
            JsonConvert.DeserializeObject<List<RootObject>>(File.ReadAllText(JsonString));
Run Code Online (Sandbox Code Playgroud)

为了保留参考身份,不允许这样做。