连载自定义集合具有附加属性,并添加到项目联播事件propertChanged [英] Serialise custom collection With additional properties and on Add to hookup item propertChanged events

查看:407
本文介绍了连载自定义集合具有附加属性,并添加到项目联播事件propertChanged的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义集合,我想与JSON.NET以连载:



我需要它这个定义集合中连载的子集合



在deserialisation我需要挂钩PropertyChanged事件为集合内的项目。



如果我通过我的收藏原样, JSON看到IEnumerable和串行化集合确定的项目,但忽略了内部的其他集合。



如果我的属性集合与[JSONObject的],将连载内部所有藏品但不是内部_list;



如果我添加[JsonProperty]到内部_list这将连载所有集合。



但由于它设置_list作为反序列化过程中一个属性的添加我的自定义集合的方法是不叫,并作为项目_list内所以的PropertyChanged事件从来没有得到勾搭上了。



我试图隐藏内部_list和一个公共的getter setter方法包装它,我想,如果反序列化期间,它使用的公共setter方法来设置内部_list我可以附加到项事件出现,但这并不能工作。



有什么反序列化期间我可以做,以获得notifyproperty改变了项目的事件在内部?

_list迷上了

编辑:我试过一个转换器:

 公共类TrackableCollectionConverter:JsonConverter 
{
公众覆盖布尔CanConvert(类型的objectType)
{
返回的objectType == typeof运算(TrackableCollectionCollection< ITrackableEntity>);
}

公众覆盖对象ReadJson(
JsonReader读者,类型的objectType,
对象existingValue,JsonSerializer串行)
{
// N.B.空值处理缺少
变种替代= serializer.Deserialize< TrackableCollectionCollection< ITrackableEntity>>(读卡器);


变种trackableCollection =新TrackableCollectionCollection< ITrackableEntity>();
的foreach(VAR EL在代理)
trackableCollection.Add(EL);

的foreach(VAR EL在surrogate.NewItems)
trackableCollection.NewItems.Add(EL);

的foreach(VAR EL在surrogate.ModifiedItems)
trackableCollection.ModifiedItems.Add(EL);

的foreach(VAR EL在surrogate.DeletedItems)
trackableCollection.DeletedItems.Add(EL);

返回trackableCollection;
}

公共覆盖无效WriteJson(JsonWriter作家,对象的值,
JsonSerializer串行)
{
serializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
serializer.Serialize(作家,价值);
}

}



给出错误:




{消息:发生错误,ExceptionMessage:在'ObjectContent`1类型没有序列化反应机构内容类型应用/ JSON的;字符集= UTF-8',ExceptionType。:System.InvalidOperationException,堆栈跟踪:空的InnerException:{消息:出现错误, ExceptionMessage:国有财产令牌属性名会导致一个无效的JSON对象路径'[0]',ExceptionType。:Newtonsoft.Json.JsonWriterException,堆栈跟踪:在Newtonsoft.Json.JsonWriter。自动完成(JsonToken tokenBeingWritten)\r\\\
在Newtonsoft.Json.JsonWriter.InternalWritePropertyName(字符串名称)\r\\\
在Newtonsoft.Json.JsonTextWriter.WritePropertyName(字符串名称,布尔逃生)\r\\\
在Newtonsoft.Json.Serialization.JsonProperty.WritePropertyName(JsonWriter作家)\r\\\
在Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter作家,对象的值,JsonObjectContract合同,JsonProperty成员,JsonContainerContract collectionContract,JsonProperty containerProperty)\\在Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList \\r\\\
在Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter作家,对象的值,JsonContract valueContract,JsonProperty成员,JsonContainerContract containerContract,JsonProperty containerProperty)\r\\\
(JsonWriter作家,IEnumerable的值,JsonArrayContract合同,JsonProperty成员,JsonContainerContract collectionContract,JsonProperty containerProperty)\r\\\
在Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter作家,对象的值,JsonContract valueContract,JsonProperty成员,JsonContainerContract containerContract ,JsonProperty containerProperty在Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter,对象的值,类型的objectType)\r\\\
)\r\\\
在Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter,对象的值,类型的objectType在Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter,对象的值)\r\\\
在System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(类型类型,对象的值)\r\\\
,流writeStream,编码effectiveEncoding)\r\\\
在System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStream(类型类型,对象的值,流writeStream,编码effectiveEncoding)\r\\\
在System.Net.Http。 Formatting.BaseJsonMediaTypeFormatter.WriteToStream(类型类型,对象的值,流writeStream,HttpContent内容)\r\\\
在System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(类型类型,对象的值,流writeStream,HttpContent内容,TransportContext transportContext,的CancellationToken的CancellationToken)\r\\\
---从以前的位置堆栈跟踪,其中引发异常--- \r\\\
在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)结束\ r\\\
在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)\r\\\
在System.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\\\
在System.Web.Http.WebHost .HttpControllerHandler.d__1b.MoveNext()}}




这里是收集,因为我有这么远。

  [Serializable接口] 
[JSONObject的]
[JsonConverter(typeof运算(TrackableCollectionConverter))]
公共类TrackableCollectionCollection< T> :IList的< T>其中T:ITrackableEntity
{
[JsonIgnore]
&IList的LT; T> _list =新的List< T>();

[JsonProperty]
公众的IList< T>表
{
{返回_list; }

{
_list =价值;

的foreach(在_list VAR项)
item.PropertyChanged + = item_PropertyChanged;
}
}

[数据成员]
公众的IList< T> NewItems
{
{返回_newItems; }
}
&IList的LT; T> _newItems =新的List< T>();

[数据成员]
公众的IList< T> ModifiedItems
{
{返回_modifiedChildren; }
}
&IList的LT; T> _modifiedChildren =新的List< T>();

[数据成员]
公众的IList< T> DeletedItems
{
{返回_deletedItems; }
}
&IList的LT; T> _deletedItems =新的List< T>(); T>的IEnumerable

公众的IEnumerator<的

#地区的实施情况;的GetEnumerator()
{
返回_list.GetEnumerator();
}

的IEnumerator IEnumerable.GetEnumerator()
{
返回的GetEnumerator();
} $ B的ICollection<的
$ B #endregion

#地区的实施情况; T>

公共无效添加(T项目)
{
如果(item.Id.Equals(默认值(GUID)))
_newItems.Add(项目);
,否则
{
//我想过这样做,但将螺丝EF对象生成。
//抛出新NotSupportedException异常();
}

item.PropertyChanged + = item_PropertyChanged;

_list.Add(项目);
}


公共无效清除()
{
NewItems.Clear();
ModifiedItems.Clear();

的foreach(在_list VAR项)
{
item.PropertyChanged - = item_PropertyChanged;
DeletedItems.Add(项目);
}

_list.Clear();
}

公共BOOL包含(T项目)
{
返回_list.Contains(项目);
}

公共无效CopyTo从(T []数组,INT arrayIndex)
{
_list.CopyTo(数组,arrayIndex);
}

公共BOOL删除(T项目)
{
如果(NewItems.Contains(项目))
NewItems.Remove(项目);

如果(ModifiedItems.Contains(项目))
ModifiedItems.Remove(项目);

如果
DeletedItems.Add(项目)(DeletedItems.Contains(项目)!);

返回_list.Remove(项目);
}

公众诠释伯爵
{
{返回_list.Count; }
}

公共BOOL IsReadOnly
{
{返回_list.IsReadOnly; }
} $ B的IList<的
$ B #endregion

#地区的实施情况; T>

公众诠释的IndexOf(T项目)
{
返回_list.IndexOf(项目);
}

公共无效插入(INT指数,T项目)
{
如果(item.Id.Equals(默认值(GUID)))
_newItems.Add(项目);
,否则
{
//我想过这样做,但将螺丝EF对象生成。
//抛出新NotSupportedException异常();
}

item.PropertyChanged + = item_PropertyChanged;

_list.Insert(索引项);
}

公共无效RemoveAt移除(INT指数)
{
VAR项目=本[指数]

如果(NewItems.Contains(项目))
NewItems.Remove(项目);

如果(ModifiedItems.Contains(项目))
ModifiedItems.Remove(项目);

如果
DeletedItems.Add(项目)(DeletedItems.Contains(项目)!);

_list.RemoveAt(指数);
}

公共牛逼这个[INT指数]
{
{返回_list [指数] }
集合{_list [指数] =值; }
}
#endregion
无效item_PropertyChanged(对象发件人,System.ComponentModel.PropertyChangedEventArgs E)
{
如果(((T)发送方).Id.Equals (默认值(GUID)))
的回报; //该项目已经在newItems收集

如果(ModifiedItems.Contains((T)发送者))
的回报;

ModifiedItems.Add((T)发送者);

}
}


解决方案

您可以序列自定义容器作为的JSONObject ,因为你现在正在做,并序列嵌入列表作为代理的 的ObservableCollection< T> 。然后,你可以听在添加和移除到代理,并相应地处理它们。注 - 无需定制JsonConverter。因为我没有你的 ITrackableEntity ,这里有一个快速的原型包装的IList<定义; T> 列表< T>

  [Serializable接口] 
[的JSONObject]
公共类ListContainer< T> :IList的< T>
{
[JsonIgnore]
只读表< T> _list =新的List< T>();

[JsonProperty(列表)]
私人的IList< T> SerializableList
{
得到
{
变种代理=新的ObservableCollection< T>(_清单);
proxy.CollectionChanged + =新System.Collections.Specialized.NotifyCollectionChangedEventHandler(proxy_CollectionChanged);
返回代理;
}

{
_list.Clear();
_list.AddRange(值);
}
}

无效proxy_CollectionChanged(对象发件人,System.Collections.Specialized.NotifyCollectionChangedEventArgs E)
{
如果(e.Action ==系统.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
的foreach(在e.NewItems.Cast< VAR项目; T>())
添加(项目);
}
,否则如果(e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
{
的foreach(在e.NewItems.Cast< VAR项目; T>( ))
。删除(项目);
}
,否则
{
Debug.Assert的(假);
抛出新NotImplementedException();
}
}

[JsonIgnore]
公众诠释伯爵
{
{返回_list.Count; }
}

[JsonIgnore]
公共BOOL IsReadOnly
{
{返回((IList的< T>)_名单).IsReadOnly; }
}

//超越一切这里是样板。

#地区的IList< T>会员

公众诠释的IndexOf(T项目)
{
返回_list.IndexOf(项目);
}

公共无效插入(INT指数,T项目)
{
_list.Insert(索引项);
}

公共无效RemoveAt移除(INT指数)
{
_list.RemoveAt(指数);
}

公共牛逼这个[INT指数]
{
得到
{
返回_list [指数]
}

{
_list [指数] =值;
}
}

#endregion

#地区的ICollection< T>会员

公共无效添加(T项目)
{
_list.Add(项目);
}

公共无效清除()
{
_list.Clear();
}

公共BOOL包含(T项目)
{
返回_list.Contains(项目);
}

公共无效CopyTo从(T []数组,INT arrayIndex)
{
_list.CopyTo(数组,arrayIndex);
}

公共BOOL删除(T项目)
{
返回_list.Remove(项目);
}

#endregion

#地区的IEnumerable< T>会员

公众的IEnumerator< T>的GetEnumerator()
{
返回_list.GetEnumerator();
}

#endregion

#地区的IEnumerable会员

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
返回的GetEnumerator();
}

#endregion
}

和然后,进行测试:

 公共静态无效TestListContainerJson()
{
无功名单=新ListContainer< INT>();
list.Add(101);
list.Add(102);
list.Add(103);

VAR JSON = JsonConvert.SerializeObject(名单);
VAR newList = JsonConvert.DeserializeObject< ListContainer< INT>>(JSON);
Debug.Assert的(list.SequenceEqual(newList)); //没有断言。
}



更新



原来,Json.NET遵循相同的模式的 的XmlSerializer :如果您序列化代理列表作为的阵列的,二传手将被称为用后完全填充的阵列读取,你可以将其添加为必需的:

  [Serializable接口] 
[的JSONObject ]
公共类ListContainer< T> :IList的< T>
{
[JsonIgnore]
只读表< T> _list =新的List< T>();

[JsonProperty(列表)]
私人T [] SerializableList
{
得到
{
返回_list.ToArray() ;
}

{
清除();
的foreach(价值VAR项)
添加(项目);
}
}

[JsonIgnore]
公众诠释伯爵
{
{返回_list.Count; }
}

[JsonIgnore]
公共BOOL IsReadOnly
{
{返回((IList的< T>)_名单).IsReadOnly; }
}

//超越一切这里是样板。
}

这是比我的第一个解决方案干净多了。



此外,我怀疑你的 NewItems ModifiedItems 列表包含在项目的引用主 _list 。默认情况下Json.NET将有效地序列化和放大器中克隆这些;反序列化。为了避免这种情况,寻找到 PreserveReferencesHandling 功能。更多这里


I have a custom collection which I would like to serialise with JSON.NET:

I need it to serialise the child collections within this custom collection.

On deserialisation I need to hook up PropertyChanged event for items within the collection.

If I pass my collection as is, Json sees IEnumerable and serialises the items in the collection ok, but ignores the other collections within.

If I attribute the collection with [JsonObject] it will serialise all the internal collections but not the internal _list;

if I add [JsonProperty] to the internal _list it will serialise all collections.

But since it sets the _list as a property during deserialization The Add Method of my custom collection is not called and as a therefore the propertyChanged events of the items within _list never get hooked up.

I tried hiding the internal _list and wrapping it with a public getter setter, I thought if during deserialization it used the public setter to set the internal _list I could attach to the item events there, but that does not work either.

Is there anything I can do to during deserialization to get the notifyproperty changed events of the items in the internal _list hooked up?

Edit: I tried a converter:

public class TrackableCollectionConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(TrackableCollectionCollection<ITrackableEntity>);
    }

    public override object ReadJson(
        JsonReader reader, Type objectType,
        object existingValue, JsonSerializer serializer)
    {
        // N.B. null handling is missing
        var surrogate = serializer.Deserialize<TrackableCollectionCollection<ITrackableEntity>>(reader);


        var trackableCollection = new TrackableCollectionCollection<ITrackableEntity>();
        foreach (var el in surrogate)
            trackableCollection.Add(el);

        foreach (var el in surrogate.NewItems)
            trackableCollection.NewItems.Add(el);

        foreach (var el in surrogate.ModifiedItems)
            trackableCollection.ModifiedItems.Add(el);

        foreach (var el in surrogate.DeletedItems)
            trackableCollection.DeletedItems.Add(el);

        return trackableCollection;
    }

    public override void WriteJson(JsonWriter writer, object value,
                                   JsonSerializer serializer)
    {
        serializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        serializer.Serialize(writer, value);
    }

}

Gives error:

{"Message":"An error has occurred.","ExceptionMessage":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.","ExceptionType":"System.InvalidOperationException","StackTrace":null,"InnerException":{"Message":"An error has occurred.","ExceptionMessage":"Token PropertyName in state Property would result in an invalid JSON object. Path '[0]'.","ExceptionType":"Newtonsoft.Json.JsonWriterException","StackTrace":" at Newtonsoft.Json.JsonWriter.AutoComplete(JsonToken tokenBeingWritten)\r\n at Newtonsoft.Json.JsonWriter.InternalWritePropertyName(String name)\r\n at Newtonsoft.Json.JsonTextWriter.WritePropertyName(String name, Boolean escape)\r\n at Newtonsoft.Json.Serialization.JsonProperty.WritePropertyName(JsonWriter writer)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)\r\n at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)\r\n at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value)\r\n at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)\r\n at System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)\r\n at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content)\r\n at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n at System.Web.Http.WebHost.HttpControllerHandler.d__1b.MoveNext()"}}

here is the collection as I have it so far.

[Serializable]
[JsonObject]
[JsonConverter(typeof(TrackableCollectionConverter))]
public class TrackableCollectionCollection<T> : IList<T> where T : ITrackableEntity
{
    [JsonIgnore]
    IList<T> _list = new List<T>();

    [JsonProperty]
    public IList<T> List
    {
        get { return _list; }
        set 
        { 
            _list = value; 

            foreach(var item in _list)
                item.PropertyChanged += item_PropertyChanged;
        }
    } 

    [DataMember]
    public IList<T> NewItems
    {
        get { return _newItems; }
    }
    IList<T> _newItems = new List<T>();

    [DataMember]
    public IList<T> ModifiedItems
    {
        get { return _modifiedChildren; }
    }
    IList<T> _modifiedChildren = new List<T>();

    [DataMember]
    public IList<T> DeletedItems
    {
        get { return _deletedItems; }
    }
    IList<T> _deletedItems = new List<T>();

    #region Implementation of IEnumerable

    public IEnumerator<T> GetEnumerator()
    {
        return _list.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion

    #region Implementation of ICollection<T>

    public void Add(T item)
    {
        if (item.Id.Equals(default(Guid)))
            _newItems.Add(item);
        else
        {
            // I thought about doing this but that would screw the EF object generation.
            // throw new NotSupportedException("");
        }

        item.PropertyChanged += item_PropertyChanged;

        _list.Add(item);
    }


    public void Clear()
    {
        NewItems.Clear();
        ModifiedItems.Clear();

        foreach(var item in _list)
        {
            item.PropertyChanged -= item_PropertyChanged;
            DeletedItems.Add(item);
        }

        _list.Clear();
    }

    public bool Contains(T item)
    {
        return _list.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        _list.CopyTo(array, arrayIndex);
    }

    public bool Remove(T item)
    {
        if (NewItems.Contains(item))
            NewItems.Remove(item);

        if (ModifiedItems.Contains(item))
            ModifiedItems.Remove(item);

        if (!DeletedItems.Contains(item))
            DeletedItems.Add(item);

        return _list.Remove(item);
    }

    public int Count
    {
        get { return _list.Count; }
    }

    public bool IsReadOnly
    {
        get { return _list.IsReadOnly; }
    }

    #endregion

    #region Implementation of IList<T>

    public int IndexOf(T item)
    {
        return _list.IndexOf(item);
    }

    public void Insert(int index, T item)
    {
        if (item.Id.Equals(default(Guid)))
            _newItems.Add(item);
        else
        {
            // I thought about doing this but that would screw the EF object generation.
            // throw new NotSupportedException("");
        }

        item.PropertyChanged += item_PropertyChanged;

        _list.Insert(index, item);
    }

    public void RemoveAt(int index)
    {
        var item = this[index];

        if (NewItems.Contains(item))
            NewItems.Remove(item);

        if (ModifiedItems.Contains(item))
            ModifiedItems.Remove(item);

        if (!DeletedItems.Contains(item))
            DeletedItems.Add(item);

        _list.RemoveAt(index);
    }

    public T this[int index]
    {
        get { return _list[index]; }
        set { _list[index] = value; }
    }
    #endregion
    void item_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (((T)sender).Id.Equals(default(Guid)))
            return; // The Item is already in the newItems collection

        if (ModifiedItems.Contains((T)sender))
            return;

        ModifiedItems.Add((T)sender);

    }
}

解决方案

You could serialize your custom container as a JsonObject, as you are doing now, and serialize the embedded list as a proxy ObservableCollection<T>. You can then listen in for additions and removals to the proxy and handle them accordingly. Note -- no custom JsonConverter required. Since I don't have your definition for ITrackableEntity, here's a quick prototype wrapper IList<T> for a List<T>:

[Serializable]
[JsonObject]
public class ListContainer<T> : IList<T> 
{
    [JsonIgnore]
    readonly List<T> _list = new List<T>();

    [JsonProperty("List")]
    private IList<T> SerializableList
    {
        get
        {
            var proxy = new ObservableCollection<T>(_list);
            proxy.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(proxy_CollectionChanged);
            return proxy;
        }
        set
        {
            _list.Clear();
            _list.AddRange(value);
        }
    }

    void proxy_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
        {
            foreach (var item in e.NewItems.Cast<T>())
                Add(item);
        }
        else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
        {
            foreach (var item in e.NewItems.Cast<T>())
                Remove(item);
        }
        else
        {
            Debug.Assert(false);
            throw new NotImplementedException();
        }
    }

    [JsonIgnore]
    public int Count
    {
        get { return _list.Count; }
    }

    [JsonIgnore]
    public bool IsReadOnly
    {
        get { return ((IList<T>)_list).IsReadOnly; }
    }

    // Everything beyond here is boilerplate.

    #region IList<T> Members

    public int IndexOf(T item)
    {
        return _list.IndexOf(item);
    }

    public void Insert(int index, T item)
    {
        _list.Insert(index, item);
    }

    public void RemoveAt(int index)
    {
        _list.RemoveAt(index);
    }

    public T this[int index]
    {
        get
        {
            return _list[index];
        }
        set
        {
            _list[index] = value;
        }
    }

    #endregion

    #region ICollection<T> Members

    public void Add(T item)
    {
        _list.Add(item);
    }

    public void Clear()
    {
        _list.Clear();
    }

    public bool Contains(T item)
    {
        return _list.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        _list.CopyTo(array, arrayIndex);
    }

    public bool Remove(T item)
    {
        return _list.Remove(item);
    }

    #endregion

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()
    {
        return _list.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion
}

And then, to test:

    public static void TestListContainerJson()
    {
        var list = new ListContainer<int>();
        list.Add(101);
        list.Add(102);
        list.Add(103);

        var json = JsonConvert.SerializeObject(list);
        var newList = JsonConvert.DeserializeObject<ListContainer<int>>(json);
        Debug.Assert(list.SequenceEqual(newList)); // No assert.
    }

Update

It turns out that Json.NET follows the same pattern as XmlSerializer: if you serialize the proxy list as an array, the setter will be called with the fully populated array after being read, and you can add them as required:

[Serializable]
[JsonObject]
public class ListContainer<T> : IList<T>
{
    [JsonIgnore]
    readonly List<T> _list = new List<T>();

    [JsonProperty("List")]
    private T [] SerializableList
    {
        get
        {
            return _list.ToArray();
        }
        set
        {
            Clear();
            foreach (var item in value)
                Add(item);
        }
    }

    [JsonIgnore]
    public int Count
    {
        get { return _list.Count; }
    }

    [JsonIgnore]
    public bool IsReadOnly
    {
        get { return ((IList<T>)_list).IsReadOnly; }
    }

    // Everything beyond here is boilerplate.
}

This is much cleaner than my first solution.

Also, I suspect that your NewItems and ModifiedItems list contain references to items in the main _list. By default Json.NET will effectively clone these during serialization & deserialization. To avoid this, look into the PreserveReferencesHandling functionality. More here.

这篇关于连载自定义集合具有附加属性,并添加到项目联播事件propertChanged的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆