Newtonsoft.Json在.NET 5/Core和.NET Framework上的不同行为



以下程序在.NET 5(或.NET Core(和.NET Framework上运行时会产生不同的结果。

为什么行为不同?我不是在寻求去种族化问题的解决方案;我在这里的目标是了解发生了什么。

class Versioned 
{
public Version V {get; set;} = new Version(1,0);
}
static void Main(string[] args)
{
// Serialised with version Newtonsoft.Json 9.0.1
var json = "{"V":{"Major":2,"Minor":0,"Build":-1,"Revision":-1,"MajorRevision":-1,"MinorRevision":-1}}";
Console.WriteLine($".NET: {System.Environment.Version}");
Console.WriteLine($"Json.NET: {System.Reflection.Assembly.GetAssembly(typeof(Newtonsoft.Json.JsonConvert))}");
Console.WriteLine(json);

try 
{
var b = Newtonsoft.Json.JsonConvert.DeserializeObject<Versioned>(json);
Console.WriteLine(b.V);
} 
catch (Exception ex) { Console.WriteLine(ex.GetBaseException().Message); }
}

在.NET 5上:输出为(为可读性格式化(:

.NET: 5.0.1
Json.NET: Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
{
"V": {
"Major": 2,
"Minor": 0,
"Build": -1,
"Revision": -1,
"MajorRevision": -1,
"MinorRevision": -1
}
}

出现此错误:

无法将当前JSON对象(例如{"name"value"反序列化为类型"System.Version",因为该类型需要JSON字符串值才能正确反序列化。

若要修复此错误,请将JSON更改为JSON字符串值或更改反序列化类型,使其成为可以从JSON对象反序列化的普通.NET类型(例如,不是像integer这样的基元类型,也不是像array或List这样的集合类型(。JsonObjectAttribute也可以添加到类型中,以强制它从JSON对象反序列化。路径"V.Major",第1行,位置14。

在.NET Framework 4.6.2上,输出为:

.NET: 4.0.30319.42000
Json.NET: Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
{
"V": {
"Major": 2,
"Minor": 0,
"Build": -1,
"Revision": -1,
"MajorRevision": -1,
"MinorRevision": -1
}
}
1.0

此外,如果没有默认值,.NET 4.6.2上的行为将再次不同。

class Versioned
{
public Version V { get; set; }// = new Version(1, 0);
}

在.NET 5.0上,输出是相同的:

(...)
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Version' because...

在.NET Framework 4.6.2上,现在的输出是:

(...)
Version's parameters must be greater than or equal to zero.
Parameter name: build

据我所知,System.Version类在这两个.NET版本之间(在外部(没有发生任何变化(我只知道ISpanFormattable的区别(。我看了一眼源代码(.NET Core版本和.NET Framework 4.8版本(,但我看不到任何可以解释不同行为的内容。

Json.NET在.NET Core 2.2中获得了一个新的VersionConverter,它知道如何正确地序列化和反序列化Version实例。当你使用.NET Core 2.2+.时,它会自动被拾取并使用

使用VersionConverter,Json.NET希望将Version对象序列化为类似"1.0"的字符串,而不是Json对象。如果您在文章中通过在.NET Core 2.2+上序列化Versioned的新实例来创建json字符串:

var json = Newtonsoft.Json.JsonConvert.SerializeObject(new Versioned());

您会看到它返回例如{"V":"1.0"}

同样,VersionConverter只知道如何读取版本字符串,如"1.0",而不知道如何处理包含MajorMinor等的对象。

有关详细信息,请参阅本期。请参阅此处运行的代码。

最新更新