我有一个对象,它有几个使用public getter定义的集合属性,但私有setter,在这种情况下JsonConvert.PopulateObject
将反序列化的项添加到这些集合中,使现有项保持不变。
在反序列化之前清除此类成员集合时,我需要一种行为。
我尝试在标有[OnDeserializing]
属性的方法中手动清除集合。
该方法的问题在于,即使JSON字符串中不存在collection属性,它仍将清除集合。
当只清除那些实际在JSON字符串中定义的集合时,我需要一种方法。那些未定义的应该保持不变。
由于
答案 0 :(得分:4)
好的,所以在访问Json.NET资源后,我通过继承DefaultContractResolver
的自定义合约解析程序找到了以下解决方案。
我需要覆盖数组合约创建以添加反序列化回调。此时回调接收具体的集合实例,因此我们可以操作它(在这种情况下清除它)。
只要我能确定,使用它是安全的,但请随时警告这种方法的任何缺点。
注意:我是唯一一个认为这应该是默认行为的人吗?
public class CollectionClearingContractResolver : DefaultContractResolver
{
protected override JsonArrayContract CreateArrayContract(Type objectType)
{
var c = base.CreateArrayContract(objectType);
c.OnDeserializingCallbacks.Add((obj, streamingContext) =>
{
var list = obj as IList;
if (list != null && !list.IsReadOnly)
list.Clear();
});
return c;
}
}
...
public class Test {
public List<int> List { get; private set; }
public Test() {
List = new List<int>();
}
}
...
var myObj = new Test();
myObj.List.AddRange(new[] {1,2,3});
var listReference = myObj.List;
JsonConvert.PopulateObject("{ List: [4, 5, 6] }", myObj,
new JsonSerializerSettings {
ContractResolver = new CollectionClearingContractResolver(),
});
myObj.List.ShouldEqual(listReference); // didn't recreate list
myObj.List.Count.ShouldEqual(3);
myObj.List.SequenceEqual(new[] { 4, 5, 6}).ShouldBeTrue();