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

文章讲述了在Unity环境下使用NewtonSoft.Json库时,遇到Json反序列化时的Unexpectedcharacter错误,经过排查发现是由于字段名称冲突导致的类型误识别。作者提供了问题定位和解决方案的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于使用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,所以我在此做一下记录,也希望能对遇到同样问题的人有所帮助吧。

<think>好的,我现在需要解决用户遇到的Newtonsoft.Json.JsonReaderException异常,具体错误信息是“Unexpected character encountered while parsing value”。用户提供了一些引用内容,里面提到了可能的问题和解决方法。我需要仔细分析可能的原因,并给出解决方案。 首先,用户提到在解析JSON时遇到了意外字符。根据引用中的例子,比如引用[3]中的代码,用户可能错误地读取了JSON文件。例如,用StreamReader读取后直接转换为字符串的方式可能有问题,或者文件内容本身有非JSON字符。 接下来,常见的导致这个错误的原因可能有: 1. JSON数据中存在非法字符,比如BOM头、不可见字符或转义错误。 2. JSON格式不正确,比如缺少引号、括号不匹配,或者键值对格式错误。 3. 编码问题,比如文件保存的编码与解析时使用的编码不一致,导致特殊字符被错误解析。 4. 数据源本身不是有效的JSON,比如包含注释或非标准结构。 根据引用[4]中的解决方法,用户可能需要先验证JSON的有效性,使用工具进行转换,再分步反序列化。例如,先将整个JSON字符串转换为字典,再提取需要的部分进行反序列化,这样可以逐步排查问题所在。 另外,引用[3]中的错误代码可能没有正确读取文件内容。例如,StreamReader读取后直接转换为字符串可能没有调用ReadToEnd()方法,导致只获取了对象类型而不是实际内容。这会导致解析时出现空或无效的JSON字符串。 可能的解决步骤包括: 1. 检查JSON数据的有效性,使用在线工具验证格式。 2. 确保正确读取文件内容,使用ReadToEnd()获取完整字符串。 3. 处理可能的编码问题,比如使用UTF-8而不是默认编码。 4. 分步反序列化,先转为JObject或字典,再处理具体部分。 5. 使用异常处理来捕获解析错误,并输出原始数据以便检查问题字符。 需要提醒用户注意JSON中的特殊字符,比如未转义的双引号或控制字符,这些可能导致解析失败。此外,检查数据源是否包含额外的内容,如错误信息或HTML代码,而不是纯JSON。 最后,根据用户提供的引用,特别是引用[4]中的方法,建议用户分步处理JSON数据,先整体转换再提取所需部分,这样可以隔离问题并更容易找到具体的错误点。</think>为了修复Newtonsoft.Json.JsonReaderException异常中的"Unexpected character encountered while parsing value"错误,请按照以下步骤排查: ### 一、检查JSON数据源 1. **验证JSON格式有效性** 使用[JSONLint](https://jsonlint.com/)等在线工具验证原始数据,确保: - 所有字符串值使用双引号包裹 - 不存在多余的逗号(如:`{"a":1,}`) - 括号匹配完整`{}`或`[]` - 特殊字符已正确转义(例如`\"`代替`"`) 2. **检测隐藏字符** 在C#中通过以下代码检查原始数据: ```csharp string jsonString = File.ReadAllText("data.json"); Console.WriteLine("原始数据:" + jsonString); ``` ### 二、修正数据读取方式 1. **完整读取流数据** ```csharp using (StreamReader r = new StreamReader("data.json", Encoding.UTF8)) // 注意编码设置 { string json = r.ReadToEnd(); // 必须调用ReadToEnd() var obj = JsonConvert.DeserializeObject<T>(json); } ``` > 错误示例:直接转换StreamReader对象会导致获取`System.IO.StreamReader`类型字符串而非实际内容[^3] 2. **处理BOM头问题** ```csharp string json = File.ReadAllText("data.json", Encoding.UTF8).Trim('\uFEFF'); ``` ### 三、分步反序列化(推荐) ```csharp try { var rawData = JsonConvert.DeserializeObject<JObject>(jsonString); if (rawData["data"] != null) { var list = JsonConvert.DeserializeObject<List<Model>>(rawData["data"]["list"].ToString()); } } catch (JsonReaderException ex) { Console.WriteLine($"错误位置:{ex.LineNumber}行{ex.LinePosition}列"); Console.WriteLine("问题上下文:" + jsonString.Substring(ex.LinePosition-10, 20)); } ``` ### 四、编码问题处理 1. **统一使用UTF-8编码** ```csharp File.WriteAllText("data.json", jsonString, Encoding.UTF8); // 写入时指定编码 ``` 2. **自动检测编码** ```csharp using (var stream = new FileStream("data.json", FileMode.Open)) using (var reader = new StreamReader(stream, true)) // 启用自动编码检测 { string json = reader.ReadToEnd(); } ``` ### 五、特殊场景处理 1. **处理包含注释的JSON** ```csharp var settings = new JsonSerializerSettings { CommentHandling = CommentHandling.Ignore }; var obj = JsonConvert.DeserializeObject<T>(json, settings); ``` 2. **动态类型反序列化** ```csharp dynamic result = JsonConvert.DeserializeObject(json); if (result.error != null) { throw new Exception("API返回错误:" + result.error.message); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值