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

时间:2016-11-15 21:49:48

标签: 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; }
}

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

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

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

var jsonText = "{ \"SubStuff\": { } }"; 
var deser = JsonConvert.DeserializeObject<MainStuff><jsonText);

1 个答案:

答案 0 :(得分:2)

您的问题是c#Dictionary<TKey, TValue>不是covariant。即,即使SubStuff ISubStuffDictionary<string, SubStuff> is not a Dictionary<string, ISubStuff>。因此,当Json.NET尝试将Dictionary<string, SubStuff>设置回MainStuff.SubStuff属性时,会抛出InvalidCastException

有关读/写集合不协变的一般解释,请参阅this answer。它对List<T>缺乏协方差的讨论同样适用于通用词典。

您可以使用JsonProperty.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);
    }
}

示例fiddle

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

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();
    }
}

示例fiddle #2

最后,作为替代方案,您可以调查TypeNameHandling setting

的使用情况