Newtonsoft JSON自定义集合反序列化报错:无法创建并填充列表类型的解决咨询
解决Newtonsoft.Json反序列化自定义集合时的"Cannot create and populate list type"异常
这个问题的核心原因是Newtonsoft.Json在反序列化集合类型时,依赖于ICollection<T>接口来识别可填充的集合结构。你的ObservableCollectionAdvanced<T>虽然包装了ObservableCollection<T>,但只实现了IEnumerable<T>,Json.NET无法找到正确的方式来创建并填充这个自定义集合实例,所以抛出了异常。而ObservableCollection<T>本身是实现了ICollection<T>的,所以它能正常被反序列化。
解决方案:让自定义集合实现ICollection<T>接口
只需要给你的ObservableCollectionAdvanced<T>添加ICollection<T>的实现,把对应的成员委托给内部的_collection实例即可。这样Json.NET就能识别它为标准的可填充集合,同时也让你的自定义集合符合.NET的集合设计规范。
修改后的完整类代码如下:
Public Class ObservableCollectionAdvanced(Of T As INotifyPropertyChanged) Implements IEnumerable(Of T) Implements INotifyPropertyChanged Implements INotifyCollectionChanged Implements INotifyCollectionItemPropertyChanged Implements ICollection(Of T) ' 新增ICollection<T>接口实现 Private ReadOnly _collection As New ObservableCollection(Of T) Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged Public Event CollectionChanged As NotifyCollectionChangedEventHandler Implements INotifyCollectionChanged.CollectionChanged Public Event CollectionItemPropertyChanged As PropertyChangedEventHandler Implements INotifyCollectionItemPropertyChanged.CollectionItemPropertyChanged Public Sub New() AddHandler _collection.CollectionChanged, Sub(sender As Object, e As NotifyCollectionChangedEventArgs) RaiseEvent CollectionChanged(Me, e) End Sub End Sub Default Public ReadOnly Property Item(Index As Integer) As T Get If Index >= 0 AndAlso Index < _collection.Count Then Return _collection(Index) Else Return Nothing End If End Get End Property Public Sub Add(Item As T) Implements ICollection(Of T).Add If Item IsNot Nothing Then Me.AddHandlerToItem(Item) _collection.Add(Item) End If End Sub Private Sub AddHandlerToItem(Item As T) AddHandler Item.PropertyChanged, AddressOf Item_PropertyChanged End Sub Private Sub Item_PropertyChanged(sender As Object, e As PropertyChangedEventArgs) RaiseEvent CollectionItemPropertyChanged(sender, e) End Sub Public Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator Return _collection.GetEnumerator() End Function Private Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator Return Me.GetEnumerator() End Function ' --- ICollection<T>接口成员实现 --- Public ReadOnly Property Count As Integer Implements ICollection(Of T).Count Get Return _collection.Count End Get End Property Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of T).IsReadOnly Get Return False ' ObservableCollection本身不是只读集合 End Get End Property Public Sub Clear() Implements ICollection(Of T).Clear ' 清理每个元素的PropertyChanged事件处理器,避免内存泄漏 For Each item In _collection RemoveHandler item.PropertyChanged, AddressOf Item_PropertyChanged Next _collection.Clear() End Sub Public Function Contains(Item As T) As Boolean Implements ICollection(Of T).Contains Return _collection.Contains(Item) End Function Public Sub CopyTo(array() As T, arrayIndex As Integer) Implements ICollection(Of T).CopyTo _collection.CopyTo(array, arrayIndex) End Sub Public Function Remove(Item As T) As Boolean Implements ICollection(Of T).Remove If _collection.Remove(Item) Then ' 移除元素时记得解绑事件处理器 RemoveHandler Item.PropertyChanged, AddressOf Item_PropertyChanged Return True End If Return False End Function End Class
为什么这样能解决问题?
当Json.NET处理集合反序列化时,会执行以下逻辑:
- 检查目标类型是否实现了
ICollection<T>。 - 如果实现了,通过无参构造函数创建集合实例(你的类已经有了无参构造)。
- 遍历JSON中的每个元素,调用集合的
Add方法将元素添加进去。
实现ICollection<T>不仅解决了Json.NET的反序列化问题,还让你的自定义集合拥有了标准.NET集合的所有核心行为,在其他场景下使用也会更顺畅。
额外注意事项
- 你已经使用了
TypeNameHandling.All,这确保了Json.NET能正确反序列化IDevice的具体实现类(比如TorsionArmDevice),这部分不需要调整。 - 在
Clear和Remove方法中添加了解绑事件处理器的逻辑,能避免内存泄漏,这是自定义集合绑定元素事件时的最佳实践。
内容的提问来源于stack exchange,提问作者hilrol
相关产品推荐
相关产品推荐

