如何不使用Newtonsoft.JSON实现与其一致的JSON序列化与反序列化?
不依赖Newtonsoft.JSON实现Byte[]的Base64序列化/反序列化匹配
需要与使用Newtonsoft.JSON的程序生成/解析完全一致的JSON格式,但不想引入Newtonsoft的DLL。Newtonsoft会将Byte()序列化为Base64字符串,而默认的JavaScriptSerializer会把字节数组转为数字列表,导致序列化结果不兼容,反序列化时还会抛出Cannot convert object of type 'System.String' to type 'System.Byte[]'异常。
现有代码对比
Newtonsoft.JSON的序列化/反序列化逻辑
Class TestSettings Public Setting1 As Byte() Public Setting2 As Byte() End Class ' 序列化 Dim SettingsObj As Object = New TestSettings SettingsObj.Setting1 = Encoding.ASCII.GetBytes("This is setting 1") SettingsObj.Setting2 = Encoding.ASCII.GetBytes("This is setting 2") Dim JSONString As String = JsonConvert.SerializeObject(SettingsObj) ' 生成结果: {"Setting1":"VGhpcyBpcyBzZXR0aW5nIDE=","Setting2":"VGhpcyBpcyBzZXR0aW5nIDI="} ' 反序列化 Dim JSONContents As String = "{""Setting1"":""VGhpcyBpcyBzZXR0aW5nIDE="",""Setting2"":""VGhpcyBpcyBzZXR0aW5nIDI=""}" Dim ReadsettingsObj = CType(JsonConvert.DeserializeObject(JSONContents, GetType(TestSettings)), TestSettings) Dim Setting1String As String = Encoding.ASCII.GetString(ReadsettingsObj.Setting1) Dim Setting2String As String = Encoding.ASCII.GetString(ReadsettingsObj.Setting2) ' 结果: Setting1String = "This is setting 1", Setting2String = "This is setting 2"
原生JavaScriptSerializer的问题代码
' 序列化 Dim SettingsObj2 As Object = New TestSettings SettingsObj2.Setting1 = Encoding.ASCII.GetBytes("This is setting 1") SettingsObj2.Setting2 = Encoding.ASCII.GetBytes("This is setting 2") Dim jss = New JavaScriptSerializer Dim JSONString2 As String = jss.Serialize(SettingsObj2) ' 生成结果: {"Setting1":[84,104,105,115,32,105,115,32,115,101,116,116,105,110,103,32,49],"Setting2":[84,104,105,115,32,105,115,32,115,101,116,116,105,110,103,32,50]} ' 反序列化 Dim jss2 As New JavaScriptSerializer Dim Items = jss2.Deserialize(JSONContents, GetType(TestSettings)) ' 抛出异常: Cannot convert object of type 'System.String' to type 'System.Byte[]'
解决方案:自定义JavaScriptConverter处理Byte[]
JavaScriptSerializer支持自定义转换器,通过实现JavaScriptConverter来定义Byte()的序列化/反序列化规则,完全匹配Newtonsoft的Base64转换逻辑。
自定义转换器代码
Public Class ByteArrayConverter Inherits JavaScriptConverter Public Overrides Function Deserialize(dictionary As IDictionary(Of String, Object), type As Type, serializer As JavaScriptSerializer) As Object If type Is GetType(Byte()) Then Dim base64Str As String = dictionary.Values.Cast(Of String)().FirstOrDefault() If Not String.IsNullOrEmpty(base64Str) Then Return Convert.FromBase64String(base64Str) End If End If Throw New InvalidOperationException("无法转换为Byte数组") End Function Public Overrides Function Serialize(obj As Object, serializer As JavaScriptSerializer) As IDictionary(Of String, Object) Dim byteArray As Byte() = TryCast(obj, Byte()) If byteArray IsNot Nothing Then Return New Dictionary(Of String, Object) From {{"", Convert.ToBase64String(byteArray)}} End If Throw New InvalidOperationException("输入不是Byte数组") End Function Public Overrides ReadOnly Property SupportedTypes() As IEnumerable(Of Type) Get Return {GetType(Byte())} End Get End Property End Class
使用转换器的序列化代码
Dim SettingsObj2 As New TestSettings SettingsObj2.Setting1 = Encoding.ASCII.GetBytes("This is setting 1") SettingsObj2.Setting2 = Encoding.ASCII.GetBytes("This is setting 2") Dim jss = New JavaScriptSerializer ' 注册自定义转换器 jss.RegisterConverters({New ByteArrayConverter()}) Dim JSONString2 As String = jss.Serialize(SettingsObj2) ' 生成结果与Newtonsoft完全一致: {"Setting1":"VGhpcyBpcyBzZXR0aW5nIDE=","Setting2":"VGhpcyBpcyBzZXR0aW5nIDI="}
使用转换器的反序列化代码
Dim JSONContents As String = "{""Setting1"":""VGhpcyBpcyBzZXR0aW5nIDE="",""Setting2"":""VGhpcyBpcyBzZXR0aW5nIDI=""}" Dim jss2 = New JavaScriptSerializer jss2.RegisterConverters({New ByteArrayConverter()}) Dim ReadsettingsObj = CType(jss2.Deserialize(JSONContents, GetType(TestSettings)), TestSettings) Dim Setting1String2 As String = Encoding.ASCII.GetString(ReadsettingsObj.Setting1) Dim Setting2String2 As String = Encoding.ASCII.GetString(ReadsettingsObj.Setting2) ' 结果: Setting1String2 = "This is setting 1", Setting2String2 = "This is setting 2"
逻辑说明
- 序列化时:将
Byte()通过Convert.ToBase64String()转为Base64字符串,替代默认的数字数组输出 - 反序列化时:将JSON中的Base64字符串通过
Convert.FromBase64String()转回Byte(),解决类型不匹配的异常
内容的提问来源于stack exchange,提问作者Ozymandius257
相关产品推荐
相关产品推荐

