使用JSON.NET转换器通过接口值反序列化Dictionary

SYL*_*SYL 1 c# json.net deserialization

鉴于这些类定义:

public class TypeConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType) => true;

    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) => serializer.Deserialize<T>(reader);
}

public interface ISubStuff
{
    string Item { get; set; }
}

public class SubStuff : ISubStuff
{
   public string Item { get; set; }
}

public interface IMainStuff
{
    Dictionary<string, ISubStuff> SubStuff { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我尝试在方法声明中使用 TypeConverter 类进行反序列化,如下所示,但它不起作用:

public class MainStuff : IMainStuff
{ 
    [JsonConverter(typeof(TypeConverter<Dictionary<string, SubStuff>>))] 
    public Dictionary<string, ISubStuff> SubStuff
    { 
        get; 
        set; 
    } 
}
Run Code Online (Sandbox Code Playgroud)

下面对 json 进行反序列化的调用会导致unable to cast object of type Dictionary<string, SubStuff> to Dictionary<string, ISubStuff>异常。

var jsonText = "{ \"SubStuff\": { } }"; 
var deser = JsonConvert.DeserializeObject<MainStuff><jsonText);
Run Code Online (Sandbox Code Playgroud)

dbc*_*dbc 5

您的问题是 c#Dictionary<TKey, TValue>不是协变的。即,尽管SubStuff ISubStuffDictionary<string, SubStuff> 不是。 Dictionary<string, ISubStuff>因此,当 Json.NET 尝试将 back 设置Dictionary<string, SubStuff>MainStuff.SubStuff属性时,InvalidCastException会抛出异常。

有关为什么读/写集合不协变的一般解释,请参阅此答案。它对缺乏协变性的讨论List<T>同样适用于通用字典。

您可以做的是将您的onlyJsonProperty.ItemConverterType应用于字典中的值,如下所示:TypeConverter<T>

public class MainStuff : IMainStuff
{ 
    [JsonProperty(ItemConverterType = typeof(TypeConverter<SubStuff>))]
    public Dictionary<string, ISubStuff> SubStuff
    { 
        get; 
        set; 
    } 
}

public class TypeConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType) 
    {
        var msg = string.Format("This converter should be applied directly with [JsonProperty(ItemConverterType = typeof(TypeConverter<{0}>))] or [JsonProperty(typeof(TypeConverter<{0}>))]", 
                                typeof(T));
        throw new NotImplementedException(msg);
    }

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

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

小提琴样本。

顺便说一句,JsonConverter您可以继承自:CustomCreationConverter<>而不是继承自:

public class MainStuff : IMainStuff
{ 
    [JsonProperty(ItemConverterType = typeof(TypeConverter<ISubStuff, SubStuff>))]
    public Dictionary<string, ISubStuff> SubStuff
    { 
        get; 
        set; 
    } 
}

public class TypeConverter<T, TSerialized> : CustomCreationConverter<T> 
    where TSerialized : T, new()
{
    public override T Create(Type objectType)
    {
        return new TSerialized();
    }
}
Run Code Online (Sandbox Code Playgroud)

样本小提琴#2

最后,作为替代方案,您可以研究该TypeNameHandling设置的使用。