以下程序在.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"
,而不知道如何处理包含Major
、Minor
等的对象。
有关详细信息,请参阅本期。请参阅此处运行的代码。