自定义HashSet的 JSON反序列化
我在使用一个C#库,它实现了一个自定义的 HashSet<T>,名为 ObservableHashSet<T>。你可以在这里找到更多信息 这里。这里也有 ObservableHashSet的源代码。
简短版本:
在对 JsonConvert.PopulateObject 在一个 ObservableHashSet 上使用时,会创建一个新的HashSet实例(这会中断此前附加到它的可观察事件),而不是使用Clear和 Add方法来填充HashSet。
尽管 ObservableHashSet 类型确实实现了 IEnumerable 接口,但这也许还不够?如果我需要修改这个类,为了使反序列化能够正确填充对象,应该实现哪个接口?
示例
举例来说,考虑以下情况:
public class ContactLibrary
{
[JsonProperty] public ObservableHashSet<People> peoples = new ObservableHashSet<People>();
}
public class People
{
public string name;
public People(string name)
{
this.name = name;
}
}
public class Main
{
public void TestMethod()
{
//Setup objects
ContactLibrary contacts = new ContactLibrary();
contacts.peoples.CollectionChanged += Peoples_CollectionChanged;
//Add a contact
contacts.peoples.Add(new People("Charlie")); //Trigger a CollectionChanged
//Save the current contacts using json serialization
string json_save = JsonConvert.SerializeObject(contacts);
//Add a new contact
contacts.peoples.Add(new People("Emma")); //Trigger a CollectionChanged
//Actually, revert back to cancel adding the last contact
JsonConvert.PopulateObject(json_save, contacts);
//Add a new contact
contacts.peoples.Add(new People("Emily")); //DOES NOT Trigger a CollectionChanged, because people got re-instantiated.
}
private void Peoples_CollectionChanged(INotifyCollectionChangedEventArgs<People> e)
{
switch(e.Action)
{
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
Debug.Log("New people added : " + e.NewItem.name);
break;
}
}
}
我正在使用一个JSON字符串来存储类A 的一个实例的状态,并用这个字符串来还原一个先前的状态。通过这样做,JsonConvert.PopulateObject 为 ObservableHashSet<People> peoples 字段创建了一个新实例,打破了在peoples字段的第一个实例上设置的事件监听器。
解决方案
正如 @HootanHT的已删除答案中所提到的,你应该实现 ICollection<T>。这是Json.NET实际在决定是否能够就地填充集合时所查找的接口契约。Json.NET的工作逻辑如下:
- 如果属性不为null且实现
ICollection<T>,则向其中添加项。它不会调用Clear()(例如你可以拥有默认项)。 - 否则创建一个新集合。
但你不需要把它封装在另一个类型中。你可以直接派生一个实现 ICollection<T> 的新类型。大多数函数已经由基类实现,你只需要一个透传的 Add 以及 CopyTo。
public class MyObservableHashSet<T> : ObservableHashSet<T>, ICollection<T>
where T : notnull
{
public MyObservableHashSet() : base() {}
public MyObservableHashSet(int capacity) : base(capacity) {}
public MyObservableHashSet(IEqualityComparer<T>? comparer) : base(comparer) {}
public MyObservableHashSet(IEnumerable<T> collection) : base(collection) {}
public MyObservableHashSet(IEnumerable<T> collection, IEqualityComparer<T>? comparer) : base(collection, comparer) {}
void ICollection<T>.Add(T item) => Add(item);
public void CopyTo(T[] array, int arrayIndex)
{
if (Count + arrayIndex > array.Length) throw new IndexOutOfRangeException();
var i = arrayIndex;
foreach (var item in this)
array[i++] = item;
}
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。