JSON.NET: 反序列化为具有只读属性的对象会产生意外结果

JSON.NET: Deserialization into an object with read-only properties yields unexpected results

我是 JSON.NET 的新手,我正在尝试将 JSON 字符串反序列化为包含只读 属性.[=13= 的简单 .NET 对象]

我正在尝试反序列化的 JSON 包含此只读 属性(当然 "wrong" 是什么)。问题是,另一个 属性 现在没有获得 JSON 字符串中给定的值,而是只读 属性 的值。我本以为 JSON.NET 会抛出一个错误或简单地忽略只读 属性,但永远不会得到另一个 属性 只读 属性 的值。 我错过了什么吗?

或者换句话说: 为什么DeSerPerson.Communications.Items(1).ComValue 的值在getEMail 的return 语句发生变化时发生变化?

解决方法:如果它存在,我如何告诉序列化器序列化 getEmail 但反序列化器忽略它?

我在这里创建了一个fiddle:https://dotnetfiddle.net/tUMQxF 第一个答案后略作修改。

Imports System
Imports System.Collections.Generic
Imports Newtonsoft.Json

Public Class Communication

    Property ComType As Integer

    Property ComValue As String
End Class

Public Class Communications

    Private Property _fixedCommunication As New Communication With {.ComType = 2, .ComValue = "FixedEmail@web.de"}

    Public Property Items As New List(Of Communication)

    Public ReadOnly Property getEMail As Communication
        Get
            Return Items.Find(Function(x) x.ComType = 2) ' Yields unexpected result: DeSerPerson.Communications.Items(1).ComValue = Fred.Flintstone@web.de
        'Return _fixedCommunication ' Yields expected result: DeSerPerson.Communications.Items(1).ComValue = NewEmailAddress@web.de, though "error" would be a more intuitive result to me
        End Get
    End Property
End Class

Public Class Person

    Property Name As String

    Property Communications As New Communications
End Class

Public Module Deserialization

    Public Sub Main()
        'The following Json-String was the result of the following process:
        ' 1. Deserialization of Person with Email-Address Fred.Flintstone@web.de
        ' 2. Sent to javascript via WebMethod
        ' 3. In javascript the Email-Address was changed to NewEmailAddress@web.de
        ' 4. The whole object (including the read-only property) was sent back resulting in the following JSON:
        'Dim PersonJson = "
        '{
        '     'Name': 'Fred Flintstone'
        '    ,'Communications': {
        '        'Items':[
        '             {'ComType':1,'ComValue':'0711-4665'}
        '            ,{'ComType':2,'ComValue':'NewEmailAddress@web.de'}
        '            ]
        '        ,'getEMail':
        '            {'ComType':2,'ComValue':'Fred.Flintstone@web.de'}
        '    }
        '}".Replace("'", """")
        Dim PersonJson = "{'Name': 'Fred Flintstone','Communications':{'Items':[{'ComType':1,'ComValue':'0711-4665'},{'ComType':2,'ComValue':'NewEmailAddress@web.de'}],'getEMail':{'ComType':2,'ComValue':'Fred.Flintstone@web.de'}}}".Replace("'", """")
        Dim DeSerPerson = JsonConvert.DeserializeObject(Of Person)(PersonJson)
        Console.WriteLine("Result for DeSerPerson.Communications.Items(1).ComValue:")
        Console.WriteLine("--------------------------------------------------------")
        Console.WriteLine("Expected     : NewEmailAddress@web.de (or Error)")
        Console.WriteLine("but result is: " & DeSerPerson.Communications.Items(1).ComValue) ' Fred.Flintstone@web.de
    'Console.ReadLine()
    End Sub
End Module

解释很简单。反序列化器只是填充现有对象中的值,而不是创建一个新对象并将其分配给您的 属性。

请注意,Readonly 修饰符声明 属性 的值(即对对象的引用)不能更改,但 Communication 的属性不能更改对象本身。

在这种情况下,您的 getEmail 属性 return 是对 Items(1) 的引用,因为那是带有 ComType = 2 的项目。

至于"ignore"反序列化时的对象,可以很方便的使用clone方法。这样,您 return 来自 getEmail 的相同值,但不是同一个对象:

将克隆方法添加到Communication:

Public Class Communication

    Property ComType As Integer

    Property ComValue As String

    Public Function Clone() As Communication
        Return New Communication() With {.ComType = Me.ComType, .ComValue = Me.ComValue}
    End Function
End Class

Return读取属性时的克隆对象:

Public ReadOnly Property getEMail As Communication
    Get
        Return Items.Find(Function(x) x.ComType = 2).Clone() 
    End Get
End Property

当然这不是最佳代码。这只是为了向您展示它是如何工作的:)