关于使用NewtonSoft.Json库反序列化遭遇Unexpected character的解决记录

环境

Unity版本:2021.3.27f1c2
NewtonSoft.Json库:从Unity Package Manager安装

问题描述

为了保存部分设置信息,我选择使用Json序列化保存,在使用时再反序列化读取的方式。
序列化时一切正常,但当我尝试反序列化时,报出了以下错误(仅展示最后几层调用栈):

JsonReaderException: Unexpected character encountered while parsing value: {. Path ‘BPMList[0].Beat’, line 1, position 66.
Newtonsoft.Json.JsonTextReader.ReadNumberValue (Newtonsoft.Json.ReadType readType) (at <761cf2a144514d2291a678c334d49e9b>:0)
Newtonsoft.Json.JsonTextReader.ReadAsInt32 () (at <761cf2a144514d2291a678c334d49e9b>:0)
Newtonsoft.Json.JsonReader.ReadForType (Newtonsoft.Json.Serialization.JsonContract contract, System.Boolean hasConverter) (at <761cf2a144514d2291a678c334d49e9b>:0)

寻找解决方案

寻找同类遭遇

首先就是通过搜索尝试找到有同样报错的人来找到解决方案,并且也确实找到了几个,且解决方案相同,下面贴上几个:
C#解析json报错Unexpected character encountered while parsing value: . Path ‘‘, line 0, position 0.
Newtonsoft.Json Unexpected character encountered while parsing value: .Path ‘’
这两个均是因为UTF-8-BOMBOM头产生的问题,并以此解决了。

下面还有一个并非此问题但也有提到BOM头的情况
What does this JsonReaderException mean?

至少这说明BOM头确实会导致这样的异常发生,因此我也进行了尝试,但却得到了同样的报错:
unity console的报错
可以看到,BOM头的三个字节(EFBBBF)均被移除了,但仍然存在该问题,这也就说明我遇到的异常并不是BOM引起的。

另寻思路

既然他人的方法行不通,我就只能自己尝试找到解决方法。

注意到该报错的调用栈顺序是:

  1. ReadForType
  2. ReadAsInt32
  3. ReadNumberValue
    而我的Json内容是:
{
	"Name":"test",
	"MusicName":"audio",
	"BPMList":[
		{
			"BPM":60.0,
			"Beat":{
				"Beat":1,
				"UpPart":1,
				"DownPart":4
			}
		}
	],
	"MusicExt":".ogg"
}

因此我认为是反序列化时错误的将外部的Beat当作int处理了。

但当我尝试自定义序列化/反序列化(继承JsonConverter并重写)时,却发现不起作用。

找到问题

正当我一筹莫展时,突然注意到我的Json内容中,有两个同样的变量名Beat,而报错中明确的说“ReadAsInt32”。
或许… …JsonCoverter将Object的Beat错当成下面的int的Beat了?
于是我将上面的Beat改为BeatInfo,重新进行了序列化和反序列化测试,结果如下:
unity console 修改后的debuglog
可以看到没有报错,反序列化顺利完成!

结论

我不知道这属于是Json通病还是NewtonSoft.Json的问题,至少在我的这次经历中确实表现出了这样的bug:当多个字段的名称相同而类型不同时,会用错误的类型对同名字段进行反序列化,从而触发JsonReaderException: Unexpected character encountered while parsing value的异常

挺少见的一个bug,所以我在此做一下记录,也希望能对遇到同样问题的人有所帮助吧。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐