Json.net反序列化接口,具体类使用JsonConverter

时间:2012-10-09 09:18:38

标签: interface json.net deserialization converter

我的问题是,当转换器应用于接口的实现时,我的JsonConverter似乎没有被json.net反序列化过程调用,而propertytype是接口。 我使用TypeNameHandling = TypeNameHandling.Objects将$ type添加到json。我在序列化和反序列化上都这样做。 当我有一个属性接口的实现时,类'转换器被正确调用。 但是当我有一个接口类型的属性时,不会调用具体类'转换器。

当我反序列化这个类时,我的JsonDataBagCreationConverter将由RealTelephone而不是电话调用,因为这是一个接口。 即使它们都使用正确的$ type序列化。 这导致RealTelephone填充.Data,而电话.Data为空。

[JsonConverter(typeof(JsonDataBagCreationConverter<ContainerForITelephone>))]
public class ContainerForITelephone : IDataBag
{
    private object _data;
    private DataBagTypeEnum _dataBagTypeEnum;
    public ITelephone Telephone { get; set; }
    public Telephone RealTelephone { get; set; }

    public object Data
    {
        get { return _data; }
        set { _data = value; }
    }

    public DataBagTypeEnum DataBagType_Enum
    {
        get { return _dataBagTypeEnum; }
    }
}

不会为Telephone属性调用此jsonconverter。但它适用于RealTelephone。

public class JsonDataBagCreationConverter<T> : JsonConverter where T : IDataBag, new()
{       
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {           
        if (reader.TokenType != JsonToken.Null) 
        {
            var jsonObject = JObject.Load(reader);
            var target = Create(objectType, jsonObject);
            serializer.Populate(jsonObject.CreateReader(), target); 
            ((IDataBag)target).Data = jsonObject.ToString(); 
            return target;
        }
        return null;
    }

}

[JsonConverter(typeof(JsonDataBagCreationConverter<Telephone>))]
public class Telephone : ITelephone
{
    public string Name { get; set; }
    public string AreaCode { get; set; }
    public string Number { get; set; }
    public SubPhone SubPhone { get; set; }

    public object Data { get; set; }
    public DataBagTypeEnum DataBagType_Enum { get; set; }
}

我期待着您的回复,谢谢

1 个答案:

答案 0 :(得分:0)

解决:

public class JsonDataBagCreationConverter<T> : JsonConverter where T:IDataBag 
{

//, new() prevented us from using interfaces. Activator.CreateInstance did the trick in Create

//Used when the object decorated with  [JsonConverter(typeof(JsonDataBagCreationConverter<xxxx>))] is de-serialized
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var  jsonObject = JObject.Load(reader);

        if (objectType.IsInterface)
        {
            // Interfaces cannot be instantiated but must be converted to their "real" implemented type
            // Because we serialize with settings.TypeNameHandling = TypeNameHandling.Objects; 
            // A $type property is added to the json by the deserializer.
            string type = jsonObject["$type"].ToString();
            var typesAsArray = type.Split(',');
            var wrappedTarget = Activator.CreateInstance(typesAsArray[1], typesAsArray[0]);
            var realTarget = wrappedTarget.Unwrap() as IDataBag; 
            serializer.Populate(jsonObject.CreateReader(), realTarget); // Will call this function recursively for any objects that have JsonDataBagCreationConverter as attribute
            ((IDataBag)realTarget).Data = jsonObject.ToString(); // This is where custom data is stored in databag
            return realTarget; 
        }

        // Non interface
        var target = Create(objectType, jsonObject);
        serializer.Populate(jsonObject.CreateReader(), target); // Will call this function recursively for any objects that have JsonDataBagCreationConverter as attribute
        ((IDataBag)target).Data = jsonObject.ToString(); // This is where custom data is stored in databag
        return target;


}

public override bool CanRead
{
    get
    {
        return true; 
    }
}

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

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    throw new Exception("WriteJson not implemented");
}

protected IDataBag Create(Type objectType, JObject jsonObject)
{
    var aa = Activator.CreateInstance(objectType);
    return aa as IDataBag;
    // return new T(); // this demands ,new() on the class and then it will not work with interfaces
}

public override bool CanConvert(Type objectType)
{
    return typeof(T).IsAssignableFrom(objectType);
}

}