自定义SerializerSettings转换JToken为.NET类型及Json.NET反序列化疑问
嘿,针对你关于Json.NET的这两个问题,我来给你详细拆解下!
1. JsonConvert.DeserializeObject<MyType>(jsonString) 和 JsonConvert.DeserializeObject<JToken>(jsonString).ToObject<MyType>() 等价吗?
简单来说,在使用默认序列化设置的前提下,两者最终得到的MyType对象基本是等价的,但背后的执行逻辑有明显差异:
JsonConvert.DeserializeObject<MyType>(jsonString)是一步到位:直接将JSON字符串解析并映射到MyType的实例,全程基于默认(或你传入的)设置处理。- 而先转JToken再调用
ToObject<MyType>()是分两步走:先把JSON解析成JToken的DOM结构(相当于在内存中存了一份JSON的树形表示),再从这个DOM结构映射到MyType对象。
但这里有个关键前提:如果涉及自定义序列化设置,两者的结果可能就不一样了。比如你如果在解析JToken时用了某套设置,而ToObject<MyType>()会默认使用全局的默认设置,这时候最终结果就会和直接用自定义设置调用DeserializeObject<MyType>有差异。只有当两次操作(解析JToken和转对象)使用的设置完全一致时,结果才会等价。
举个实际例子:假设你的JSON里包含注释,而你需要设置CommentHandling = CommentHandling.Ignore才能正常解析。如果你直接用带这个设置的DeserializeObject<MyType>,可以顺利完成;但如果先不带这个设置解析成JToken,这一步就会因为JSON里的注释抛出异常,后续的ToObject根本没法执行。
2. 如何用自定义SerializerSettings将JToken转换为.NET类型?
你观察得很准,JToken.ToObject<T>()确实没有直接接收SerializerSettings的重载,但我们可以绕个弯,用JsonSerializer类来实现自定义设置的转换,具体步骤如下:
第一步:定义你的自定义SerializerSettings
比如你要添加自定义转换器、调整日期格式、设置空值处理规则等:
var customSettings = new JsonSerializerSettings { // 添加自定义转换器 Converters = new List<JsonConverter> { new MyCustomDateTimeConverter() }, // 自定义日期格式 DateFormatString = "yyyy-MM-dd HH:mm:ss", // 忽略空值属性 NullValueHandling = NullValueHandling.Ignore, // 其他你需要的设置 MissingMemberHandling = MissingMemberHandling.Ignore };
第二步:用设置创建JsonSerializer实例
var serializer = JsonSerializer.Create(customSettings);
第三步:通过JsonSerializer完成JToken到目标类型的转换
这里有两种常用的方式,根据你的需求选择:
- 方式一:直接反序列化得到新对象
如果还没有目标类型的实例,可以直接用Deserialize方法:
MyType targetObj = serializer.Deserialize<MyType>(myJToken.CreateReader());
- 方式二:填充已有的对象实例
如果已经创建了MyType的实例,想把JToken的数据填充进去,可以用Populate方法:
MyType targetObj = new MyType(); serializer.Populate(myJToken.CreateReader(), targetObj);
这两种方式都会严格遵循你定义的SerializerSettings,包括使用指定的转换器、日期格式等,完美解决ToObject方法无法传参的问题。
内容的提问来源于stack exchange,提问作者John

