使用DataContractJsonSerializer序列化JSON出现尾随空字符致单元测试失败
解决DataContractJsonSerializer序列化JSON出现尾随空字符导致单元测试失败的问题
问题重现
你在使用DataContractJsonSerializer序列化Currency对象时,生成的JSON字符串带有大量尾随空字符(\0),导致单元测试对比文件中的示例JSON时失败。虽然带空字符的JSON能正常反序列化,但严格的字符串对比无法通过。
相关代码如下:
原始序列化代码
public static string SerializeJSON<T>(T ObjectToSerialize) { DataContractJsonSerializer serializer = new DataContractJsonSerializer(ObjectToSerialize.GetType()); using (MemoryStream memoryStream = new MemoryStream()) { using (var jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(memoryStream, Encoding.UTF8, false, true)) { serializer.WriteObject(jsonWriter, ObjectToSerialize); } return Encoding.UTF8.GetString(memoryStream.GetBuffer()); } }
单元测试代码
[TestMethod] public void SerializeJSON() { string testJSON = File.ReadAllText(@"Util\\TestCurrency.json"); Currency currency = StaticExamples.ccy1; string json = SerializeUtil.SerializeJSON(currency); Assert.AreEqual(testJSON, json); }
Currency类定义
public class Currency { public int currencyId { get; set; } public string code { get; set; } public string name { get; set; } public string status { get; set; } }
问题根源
问题出在memoryStream.GetBuffer()这个方法上:它返回的是内存流整个预分配的底层缓冲区,而不是实际写入的有效数据。内存流会提前分配比实际需要更大的空间,未被使用的缓冲区部分会被填充为空字符(\0),所以转换成字符串后就会带有这些多余的尾随空字符。
修复方案
我们需要只读取内存流中实际写入的有效数据,有两种常用的方式:
方式一:使用StreamReader读取(你已经采用的方案)
将流的位置重置到起始处,然后用StreamReader读取所有有效数据:
public static string SerializeJSON<T>(T ObjectToSerialize) { DataContractJsonSerializer serializer = new DataContractJsonSerializer(ObjectToSerialize.GetType()); using (MemoryStream memoryStream = new MemoryStream()) { using (var jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(memoryStream, Encoding.UTF8, false, true)) { serializer.WriteObject(jsonWriter, ObjectToSerialize); } memoryStream.Position = 0; // 重置流指针到开头 return new StreamReader(memoryStream).ReadToEnd(); // 仅读取有效数据 } }
方式二:使用ToArray()获取有效字节数组
memoryStream.ToArray()会返回仅包含实际写入数据的字节数组,再转换为字符串:
public static string SerializeJSON<T>(T ObjectToSerialize) { DataContractJsonSerializer serializer = new DataContractJsonSerializer(ObjectToSerialize.GetType()); using (MemoryStream memoryStream = new MemoryStream()) { using (var jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(memoryStream, Encoding.UTF8, false, true)) { serializer.WriteObject(jsonWriter, ObjectToSerialize); } return Encoding.UTF8.GetString(memoryStream.ToArray()); // 仅转换有效数据 } }
这两种方式都能避免读取缓冲区中的空字符,生成的JSON字符串就会和文件中的示例完全一致,单元测试就能顺利通过了。
内容的提问来源于stack exchange,提问作者Erik
相关产品推荐
相关产品推荐

