JSON.NET将嵌套的接口列表解析为具体的类

Car*_*mas 2 c# json.net

我有一个自定义转换器

public class ConcreteTypeConverter<T> : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            serializer.Serialize(writer, value);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            return serializer.Deserialize<T>(reader);
        }

        public override bool CanConvert(Type objectType)
        {
            return true;
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后我有以下课程的&接口

[DataContract]
public class Health : IHealth
{
    [DataMember(Name = "status")]
    public string Status { get; set; }
    [DataMember(Name = "alerts")]
    [JsonConverter(typeof(ConcreteTypeConverter<List<Alert>>))]
    public IList<IAlert> Alerts { get; set; }
}
[DataContract]
public class Alert : IAlert
{
    [DataMember(Name = "code")]
    public string Code { get; set; }
}
public interface IAlert
{
    string Code { get; set; }
}
public interface IHealth
{
    string Status { get; set; }
    IList<IAlert> Alerts { get; set; } 
}
Run Code Online (Sandbox Code Playgroud)

如何获取转换器以将IList映射到List?

当前代码抛出

Unable to cast object of type 'System.Collections.Generic.List`1[xxx.Services.xxx.New.Alert]' to type 'System.Collections.Generic.IList`1[xxx.Services.xxx.Configuration.Model.New.IAlert]'.
Run Code Online (Sandbox Code Playgroud)

gal*_*nus 5

您的问题不是转换器,而是.Net类型的系统。List<Alert>不能强制转换为IList<IAlert>,只能强制转换为IList<Alert>,这是因为IList<T>不协变(请参见此处和其他地方的说明)。

您可以做的是为集合属性编写一个指定的转换器,该转换器负责在集合项类型之间进行转换:

public class ConcreteCollectionTypeConverter<TCollection, TItem, TBaseItem> : JsonConverter
    where TCollection : ICollection<TBaseItem>, new()
    where TItem : TBaseItem
{
    public override void WriteJson(
        JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }

    public override object ReadJson(
        JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var collection = new TCollection();
        var items = serializer.Deserialize<IEnumerable<TItem>>(reader);

        foreach (var item in items)
        {
            collection.Add(item);
        }

        return collection;
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(ICollection<TBaseItem>).IsAssignableFrom(objectType);
    }
}

[DataContract]
public class Health : IHealth
{
    [DataMember(Name = "status")]
    public string Status { get; set; }
    [DataMember(Name = "alerts")]
    [JsonConverter(
        typeof(ConcreteCollectionTypeConverter<List<IAlert>, Alert, IAlert>))]
    public IList<IAlert> Alerts { get; set; }
}
Run Code Online (Sandbox Code Playgroud)