使用NewtonsoftJSON解释ObjectCreationHandling?我正在追踪一个错误,我注意到NewtonsoftJSON将项目附加到已在默认构造函数中初始化的列表。我在C#聊天中进行了一些挖掘并与一些人讨论,我们注意到此行为并不适用于所有其他集合类型。https://dotnetfiddle.net/ikNyiT使用系统;使用Newtonsoft.Json;使用System.Collections.Generic;使用System.Collections.ObjectModel;publicclassTestClass{publicCollectionCollection=newCollection(new[]{"ABC","DEF"});publicListList=newList(new[]{"ABC","DEF"});publicReadOnlyCollectionReadOnlyCollection=newReadOnlyCollection(new[]{"ABC","DEF"});}publicclassProgram{publicstaticvoidMain(){varserialized=@"{Collection:['Goodbye','AOL'],List:['Goodbye','AOL'],ReadOnlyCollection:['Goodbye','美国在线']}”;vartestObj=JsonConvert.DeserializeObject(序列化);Console.WriteLine("testObj.Collection:"+string.Join(",",testObj.Collection));Console.WriteLine("testObj.List:"+string.Join(",",testObj.List));Console.WriteLine("testObj.ReadOnlyCollection:"+string.Join(",",testObj.ReadOnlyCollection));}}输出:testObj.Collection:ABC,DEFtestObj.List:ABC,DEF,Goodbye,AOLtestObj.ReadOnlyCollection:再见,AOL如您所见,Collection属性不受反序列化的影响,将附加List并替换ReadOnlyCollection这是预期的行为吗?是什么原因?它基本上归结为类型实例化和ObjectCreationHandling设置。ObjectCreationHandling具有三个设置Automatic0Reuseexistingobjects,在需要时创建新对象。重用1仅重用现有对象。替换2总是创建新对象。默认值为自动(第44行)。只有在确定当前类型是否具有空TypeInitializer的一系列检查后,Auto才会被覆盖。此时它检查是否存在无参数构造函数。//////创建一个工厂函数,该函数可用于创建由///参数类型描述的JsonConverter实例。///返回的函数然后可用于通过对象数组调用转换器的默认构造函数或任何///参数化构造函数。///基本上它是这样的(它看起来像6行大约1500行代码)。ObjectCreationHandlingoch=ObjectCreationHandling.Auto;if(typeInitializer==null){if(parameterlessConstructor){och=ObjectCreationHandling.Reuse;}else{och=ObjectCreationHandling.Replace;架构构造器内部组成。如上所示,每个设置都有不同的功能。回到List、Collection和ReadOnlyCollection,我们将查看每个条件语句的集合。列表testObj.List.GetType().TypeInitializer==null为假。因此,List接收默认的ObjectCreationHandling.Auto,并且在反序列化期间使用testObj实例的实例化List,以及使用序列化字符串实例化的新List。testObj.List:ABC,DEF,Goodbye,AOLcollectiontestObj.Collection.GetType().TypeInitializer==nulltr??ue表示没有可用的反射类型初始化器,所以我们进入下一步检查无参数构造的条件功能。testObj.Collection.GetType().GetConstructor(Type.EmptyTypes)==null为假。生成的Collection接收ObjectCreationHandling.Reuse的值(仅重用现有对象)。Collection的实例化实例用于testObj,但序列化后的字符串无法实例化。testObj.Collection:ABC,DEFReadOnlyCollectiontestObj.ReadOnlyCollection.GetType().TypeInitializer==nullTrue表示没有可用的反射类型初始化器,因此我们转到下一个条件,检查是否存在无参数构造函数。testObj.ReadOnlyCollection.GetType().GetConstructor(Type.EmptyTypes)==null也是如此。因此,ReadOnlyCollection接收ObjectCreationHandling.Replace的值(总是创建新对象)。仅使用序列化字符串中的实例化值。testObj.ReadOnlyCollection:再见,AOL虽然这个问题已经解决,但我本来想将这个答案发布到一个重复的问题,但那个问题已经关闭,所以我在这里发布我的答案,因为它包含一些内部视图。由于Json.NET是开源的,我们可以幸运地找到它的根源:-)。如果您查看Json.NET源代码,您可以找到处理反序列化的JsonSerializerInternalReader类(完整源代码在这里)。此类有一个方法SetPropertyValue,它在新创建的对象上设置反序列化值(代码缩写):privateboolSetPropertyValue(JsonPropertyproperty,...,objecttarget){...if(CalculatePropertyDetails(property,...useExistingValue,...)){返回false;}...if(propertyConverter!=null&&propertyConverter.CanRead){...}else{value=CreateValueInternal(...,(useExistingValue)?currentValue:null);}if((!useExistingValue||value!=currentValue)&&ShouldSetPropertyValue(property,value)){property.ValueProvider.SetValue(target,value);...返回真;}返回使用现有值;如您所见,有一个布尔值标志useExistingValue用于确定是重用还是替换现有值。CalculatePropertyDetails方法内部是以下代码片段:(目标);得到当前值=真;if(currentValue!=null){...useExistingValue=(!propertyContract.IsReadOnlyOrFixedSize&&!propertyContract.UnderlyingType.IsValueType());}}对于List底层集合,IsReadOnlyOrFixedSize返回false并且IsValueType()返回false——因此底层现有值将被重用。对于Array,IsValueType()也是false,但由于显而易见的原因,IsReadOnlyOrFixedSize为true,因此useExistingValue标志设置为false并且SetPropertyValue方法中的CreateValueInternal调用接收到空引用,这是不重用现有值的指示符,而是创建一个新实例,然后将其设置在新实例上。如前所述,可以使用ObjectCreationHandling.Replace更改此行为,因为这是在CalculatePropertyDetails方法中设置useExistingValue之前检查的。以上就是C#学习教程:使用NewtonsoftJSON讲解ObjectCreationHandling?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
