newtonsoft json 如果 class 中的目标已初始化,则将有效日期时间反序列化为可为 null 的 datetimeoffset 不同行为

newtonsoft json deserialize of valid datetime into nullable datetimeoffset different behavior if target in class was initialized

Newtonsoft JSON 今天从 NuGet(我认为是 V12)、.NET 框架 V4.7.2、Web 服务的简化示例 return 中提取出来。代码和输出如下。所有 returned 日期时间形式都声称是 UTC。当反序列化为 class 的 datetimeoffset 成员时,是否有反序列化设置选项将无时区信息视为 UTC?示例 returned 值为“2015-08-04T22:04:50”

如果 datetimeoffset 成员未标记为可为 null,则没有时区的可解析 datetimeoffset returns 默认未初始化值 (1/1/0001 12:00:00 AM +00:00)。也就是说,反序列化没有成功。使用 DateTimeOffset.Parse 解析时的相同字符串将其视为本地时区,并且 returns 是本地时区中的有效日期时间。不好,但可以用其他代码处理。

如果 datetimeoffset 成员被标记为可为空,则该成员保持为空(无),这也是不正确的。

class 中 datetimeoffset 的初始化值:8/4/2015 10:04:50 PM +00:00

Newtonsoft.Json.JsonConvert.SerializeObject 序列化字符串:{"dtoReturned":"2015-08-04T22:04:50+00:00"}

来自网络服务的序列化字符串:{"dtoReturned":"2015-08-04T22:04:50"}

datetimeoffset 的反序列化值:8/4/2015 10:04:50 PM +00:00

class 中 datetimeoffset 的未初始化值:1/1/0001 12:00:00 AM +00:00

datetimeoffset 的反序列化值:1/1/0001 12:00:00 AM +00:00

class 中 datetimeoffset 的初始化值:8/4/2025 10:04:50 PM +00:00

Newtonsoft.Json.JsonConvert.SerializeObject 序列化字符串:{"dtoReturned":"2025-08-04T22:04:50+00:00"}

来自网络服务的序列化字符串:{"dtoReturned":"2025-08-04T22:04:50"}

datetimeoffset 的反序列化值:8/4/2025 10:04:50 PM +00:00

在反序列化之前 class 中的 datetimeoffset 值什么都没有

class 中 datetimeoffset 的反序列化值什么都没有

进口System.IO Public Class Form1

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    Dim obj1a As New TestClass1 ' transfers_v1_incoming
    obj1a.dtoReturned = DateTimeOffset.Parse("2015-08-04T22:04:50Z")
    Debug.Print("initialized value of datetimeoffset in class: " & obj1a.dtoReturned.ToString)
    Dim strIn As String = Newtonsoft.Json.JsonConvert.SerializeObject(obj1a)
    Debug.Print("Newtonsoft.Json.JsonConvert.SerializeObject serialized string: " & strIn)
    strIn = Replace(strIn, "+00:00", "")
    Debug.Print("serialized string from web service: " & strIn)

    Newtonsoft.Json.JsonConvert.DeserializeObject(strIn, obj1a.GetType)
    Debug.Print("deserialzied value of datetimeoffset: " & obj1a.dtoReturned.ToString)

    Dim obj1b As New TestClass1 ' transfers_v1_incoming
    Debug.Print("uninitialized value of datetimeoffset in class: " & obj1b.dtoReturned.ToString)

    Newtonsoft.Json.JsonConvert.DeserializeObject(strIn, obj1b.GetType)
    Debug.Print("deserialzied value of datetimeoffset: " & obj1b.dtoReturned.ToString)

    Dim obj2a As New TestClass2
    obj2a.dtoReturned = DateTimeOffset.Parse("2025-08-04T22:04:50Z")
    Debug.Print("initialized value of datetimeoffset in class: " & obj2a.dtoReturned.ToString)
    strIn = Newtonsoft.Json.JsonConvert.SerializeObject(obj2a)
    Debug.Print("Newtonsoft.Json.JsonConvert.SerializeObject serialized string: " & strIn)
    strIn = Replace(strIn, "+00:00", "")
    Debug.Print("serialized string from web service: " & strIn)
    Newtonsoft.Json.JsonConvert.DeserializeObject(strIn, obj2a.GetType)
    Debug.Print("deserialzied value of datetimeoffset: " & obj2a.dtoReturned.ToString)

    Dim obj2b As New TestClass2
    If IsNothing(obj2b.dtoReturned) Then
        Debug.Print("value of datetimeoffset in class before deserialize is nothing")
    Else
        Debug.Print("uninitialized value of datetimeoffset in class before deserialize: " & obj2b.dtoReturned.ToString)
    End If

    Newtonsoft.Json.JsonConvert.DeserializeObject(strIn, obj2b.GetType)
    If IsNothing(obj2b.dtoReturned) Then
        Debug.Print("deserialzied value of datetimeoffset in class is nothing")
    Else
        Debug.Print("deserialzied value of datetimeoffset: " & obj2b.dtoReturned.ToString)
    End If

End Sub

Class TestClass1
    Public Property dtoReturned As DateTimeOffset
End Class
Class TestClass2
    Public Property dtoReturned As DateTimeOffset?
End Class

结束Class

您调用 Newtonsoft.Json.JsonConvert.DeserializeObject(strIn, obj.GetType) 就好像它要改变 obj 变量一样。不会的。

相反,您需要使用从此方法返回的对象。您还需要将其投射到您的 class.

obj = CType(Newtonsoft.Json.JsonConvert.DeserializeObject(strIn, obj.GetType), TestClass1)

或者更简单,使用采用泛型类型定义的重载:

obj = Newtonsoft.Json.JsonConvert.DeserializeObject(Of TestClass1)(strIn)