JSON.NET(de)序列化对象引用

时间:2014-03-14 14:32:43

标签: c# object serialization reference json.net

如果我序列化对象的引用,则将它们序列化为原始对象的完整副本。如果对象被多次使用,则会产生大量开销。 我想要的是,对象引用列表被序列化为一个object-id列表,当反序列化反转回对象引用时。

使用自定义转换器,我设法让序列化按我的意愿工作。但是当反序列化时我遇到的问题是我无法弄清楚如何访问已经反序列化的MyListItem列表来引用列表中的对象。

这是我到目前为止所得到的:

public class MyListItem
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class MyObject
{
    public string Name { get; set; }
    [JsonConverter(typeof(ListIdOnlyConverter))]
    public List<MyListItem> Items = new List<MyListItem>();
}

public class MyWrapper
{
    public List<MyListItem> Items = new List<MyListItem>();
    public List<MyObject> Objects = new List<MyObject>();
}

public class ListIdOnlyConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsClass;
    }

    // convert the List<MyListItem> to a List<[MyListItem.Id]>
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteStartArray();
        var list = (IEnumerable<object>)value;
        foreach (var item in list)
            writer.WriteValue(GetId(item));
        writer.WriteEndArray();
    }

    // get the item id with reflection
    private int GetId(object obj)
    {
        var prop = obj.GetType().GetProperty("Id", typeof(int));
        if (prop != null && prop.CanRead)
        {
            return (int)prop.GetValue(obj, null);
        }
        return 0;
    }

    // convert the List<[MyListItem.Id]> to a List<MyListItem>
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jArray = JArray.Load(reader);

        var list = (List<object>)existingValue;

        foreach (var entry in jArray)
        {
            // and here comes the problem
            // instead of adding new instances with just the id set I need references to the previously deserialized objects in wrapper.Items
            list.Add(new MyListItem { Id = (int)entry });
        }

        return list;
    }
}

[TestMethod]
public void Serialize()
{
    var wrapper = new MyWrapper();
    wrapper.Items.Add(new MyListItem { Id = 1, Name = "Item 1" });
    wrapper.Items.Add(new MyListItem { Id = 2, Name = "Item 2" });
    wrapper.Items.Add(new MyListItem { Id = 3, Name = "Item 3" });

    var objectWithItem1 = new MyObject();
    objectWithItem1.Name = "objectWithItem1";
    objectWithItem1.Items.Add(wrapper.Items[0]);
    wrapper.Objects.Add(objectWithItem1);

    var objectWithItem2 = new MyObject();
    objectWithItem2.Name = "objectWithItem2";
    objectWithItem2.Items.Add(wrapper.Items[1]);
    wrapper.Objects.Add(objectWithItem2);

    var objectWithItem3 = new MyObject();
    objectWithItem3.Name = "objectWithItem3";
    objectWithItem3.Items.Add(wrapper.Items[2]);
    wrapper.Objects.Add(objectWithItem3);

    var objectWithItem1And3 = new MyObject();
    objectWithItem1And3.Name = "objectWithItem1And3";
    objectWithItem1And3.Items.Add(wrapper.Items[0]);
    objectWithItem1And3.Items.Add(wrapper.Items[2]);
    wrapper.Objects.Add(objectWithItem1And3);

    var settings = new JsonSerializerSettings();
    var text = JsonConvert.SerializeObject(wrapper, Newtonsoft.Json.Formatting.Indented, settings);

    // this is the part not working - see ListIdOnlyConvert.ReadJson(...)
    var obj = ((MyWrapper)JsonConvert.DeserializeObject(text, typeof(MyWrapper)));
}

这是序列化时的结果:

{
    Items: [
        { "Id": 1, "Name": "Item 1" },
        { "Id": 2, "Name": "Item 2" },
        { "Id": 3, "Name": "Item 3" }
    ]
    Objects: [
        { "Name": "objectWithItem1", "Items": [1] },
        { "Name": "objectWithItem2", "Items": [2] },
        { "Name": "objectWithItem3", "Items": [3] },
        { "Name": "objectWithItem1And3", "Items": [1,3] }       
    ]
}

0 个答案:

没有答案