1

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

当我反序列化此类时,我的 JsonDataBagCreationConverter 将由 RealTelephone 调用,但不会由 Telephone 调用,因为这是一个接口。即使它们都使用正确的 $type 序列化。这导致 RealTelephone 的 .Data 被填充,而 Telephones .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; }
}

我期待着您的回音,谢谢

4

1 回答 1

1

解决了:

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

}

于 2012-10-10T08:34:27.700 回答