C# 使用附加属性序列化自定义集合,并在添加到连接项propertChanged事件时序列化自定义集合
我有一个自定义集合,我想用JSON.NET序列化它: 我需要它来序列化此自定义集合中的子集合 在反序列化时,我需要为集合中的项连接PropertyChanged事件 如果按原样传递集合,Json会看到IEnumerable并序列化集合中的项,但会忽略其中的其他集合 如果我使用[JsonObject]属性集合,它将序列化所有内部集合,但不会序列化内部_列表 如果我将[JsonProperty]添加到内部_列表中,它将序列化所有集合 但是,由于它在反序列化期间将_列表设置为属性,因此不会调用自定义集合的Add方法,因此_列表中项目的propertyChanged事件永远不会连接起来 我试图隐藏内部_列表并用公共getter setter包装它,我认为如果在反序列化过程中它使用公共setter来设置内部_列表,我可以附加到那里的项目事件,但这也不起作用 在反序列化过程中,我可以做些什么来连接内部列表中项目的notifyproperty changed事件吗 编辑:我尝试了一个转换器:C# 使用附加属性序列化自定义集合,并在添加到连接项propertChanged事件时序列化自定义集合,c#,json.net,C#,Json.net,我有一个自定义集合,我想用JSON.NET序列化它: 我需要它来序列化此自定义集合中的子集合 在反序列化时,我需要为集合中的项连接PropertyChanged事件 如果按原样传递集合,Json会看到IEnumerable并序列化集合中的项,但会忽略其中的其他集合 如果我使用[JsonObject]属性集合,它将序列化所有内部集合,但不会序列化内部_列表 如果我将[JsonProperty]添加到内部_列表中,它将序列化所有集合 但是,由于它在反序列化期间将_列表设置为属性,因此不会调用自定义集
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);
}
}
公共类TrackableCollectionConverter:JsonConverter
{
公共覆盖布尔CanConvert(类型objectType)
{
return objectType==typeof(TrackableCollectionCollection);
}
公共重写对象ReadJson(
JsonReader阅读器,类型objectType,
对象存在值,JsonSerializer序列化程序)
{
//注意:缺少空处理
变量代理=序列化程序。反序列化(读取器);
var trackableCollection=新的TrackableCollectionCollection();
foreach(代理中的变量el)
trackableCollection.Add(el);
foreach(代理项中的变量el.NewItems)
trackableCollection.NewItems.Add(el);
foreach(代理.ModifiedItems中的变量el)
trackableCollection.ModifiedItems.Add(el);
foreach(代理.DeletedItems中的变量el)
trackableCollection.DeletedItems.Add(el);
返回可跟踪收集;
}
公共重写void WriteJson(JsonWriter writer,对象值,
JsonSerializer(序列化程序)
{
serializer.ReferenceLoopHandling=ReferenceLoopHandling.Ignore;
serializer.Serialize(writer,value);
}
}
给出错误:
{“Message”:“发生了错误”。,“ExceptionMessage”:“ObjectContent`1”类型未能序列化内容类型“application/json;charset=utf-8”的响应正文。”,“ExceptionType”:“System.InvalidOperationException”,“StackTrace”:null,“InnerException”:{“Message”:“发生了错误”。,“ExceptionMessage”:”:“状态属性中的令牌属性名称将导致无效的JSON对象。路径“[0]”,“异常类型”:“Newtonsoft.JSON.jsonwritereException”,“StackTrace”:“at Newtonsoft.JSON.JsonWriter.AutoComplete(JsonToken tokenbeingwrite)\r\n at Newtonsoft.JSON.JsonWriter.InternalWritePropertyName(字符串名称)\r\n位于Newtonsoft.Json.JsonTextWriter.WritePropertyName(字符串名称,布尔转义)\r\n位于Newtonsoft.Json.Serialization.JsonProperty.WritePropertyName(JsonWriter-writer)\r\n位于Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter编写器,对象值,JsonObjectContract合约,JsonProperty成员,JsonContainerContract collectionContract,JsonProperty containerProperty)\r\n位于Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.serializationValue(JsonWriter编写器,对象值,JsonContract valueContract,JsonProperty成员,JsonContainerContract containerContract,JsonProperty containerProperty)\r\n位于Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter-writer,IEnumerable-values,JsonArrayContract-contract,JsonProperty成员,JsonContainerContract-collectionContract,JsonProperty-containerProperty)\r\n位于Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter编写器,对象值,JsonContract valueContract,JsonProperty成员,JsonContainerContract containerContract,JsonProperty containerProperty)\r\n位于Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter JsonWriter,对象值,类型objectType)\r\n位于Newtonsoft.Json.JsonSerializer.serializer\n(JsonWriter JsonWriter,对象值,类型objectType)\r\n位于Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter JsonWriter,对象值)\r\n位于System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(类型类型,对象值,流writeStream writeStream,Encoding effectiveEncoding)\r\n位于System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStream(类型、对象值、流writeStream、编码有效编码)\r\n位于System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(类型、对象值、流writeStream、HttpContent)\r\n位于System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(类型类型、对象值、流writeStream、HttpContent内容、TransportContext TransportContext、CancellationToken CancellationToken)\r\n---从引发异常的上一个位置开始的堆栈结束跟踪----\r\n在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务任务)\r\n在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务任务任务)\r\n在System.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n位于System.Web.Http.WebHost.HttpControllerHandler.d_u1b.MoveNext()“}
这是我目前的收藏
[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);
}
}
[可序列化]
[JsonObject]
[JsonConverter(类型(TrackableCollectionConverter))]
公共类TrackableCollectionCollection:IList其中T:ITrackableEntity
{
[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
}
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.
}
[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.
}
public class TrackableCollectionConverter<TEntity, TDeserialiseType> : JsonConverter where TEntity: ITrackableEntity
{
public override bool CanConvert(Type objectType)
{
return true;
//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<TDeserialiseType>(reader) as TrackableCollectionCollection<TEntity>;
var trackablecollection = new TrackableCollectionCollection<TEntity>();
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);
}
}
[JsonObject(IsReference = true)]
[DataContract(IsReference = true)]
public class Parent : TrackableEntityBase
{
[DataMember]
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ParentId
{
get { return base.Id ; }
set
{
if (base.Id.Equals(default(Guid)))
base.Id = value;
if (base.Id.Equals(value))
return;
throw new InvalidOperationException("Primary Keys cannot be changed once set.");
}
}
[DataMember]
public String Name
{
get { return _name; }
set
{
if (!String.IsNullOrWhiteSpace(_name) && _name.Equals(value, StringComparison.Ordinal))
{
return;
}
_name = value;
OnPropertyChanged("Name");
}
}
String _name;
[DataMember]
[JsonConverter(typeof(TrackableCollectionConverter<Child, TrackableCollectionCollection<Child>>))]
public virtual TrackableCollectionCollection<Child> Children { get; set; }
}
{"$id":"1","ParentId":"6d884973-5060-e411-8265-cffad877042b","Name":"Parent1","Children":{"List":[{"$id":"2","ChildId":"5bd66353-3f61-e411-8265-cffad877042b","ParentId":"6d884973-5060-e411-8265-cffad877042b","Name":"Billy","Parent":{"$ref":"1"},"Id":"5bd66353-3f61-e411-8265-cffad877042b","IsModified":true}],"NewItems":[],"ModifiedItems":[{"$ref":"2"}],"DeletedItems":[],"Count":1,"IsReadOnly":false},"Id":"6d884973-5060-e411-8265-cffad877042b","IsModified":true}