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

时间:2016-03-01 12:00:37

标签: vb.net json.net json-deserialization

我是JSON.NET的新手,我试图将JSON字符串反序列化为包含只读属性的简单.NET对象。

我试图反序列化的JSON包含这个只读属性(当然是"错误")。问题是,另一个属性现在不能获得JSON字符串中给出的值,而是获取只读属性的值。我原以为JSON.NET会抛出错误或者只是忽略只读属性,但永远不会让另一个属性成为只读属性的值。 我错过了什么吗?

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

作为一种解决方法:我如何告诉序列化程序序列化getEmail,但是如果它存在则反序列化器会忽略它?

我在这里创造了一个小提琴: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

1 个答案:

答案 0 :(得分:0)

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

请注意,results[0]修饰符指出属性的值(即对象的引用)无法更改,但不能更改Readonly对象本身的属性。< / p>

在这种情况下,您的Communication属性会返回对getEmail的引用,因为这是Items(1)项。

至于&#34;忽略&#34;反序列化时的对象,可以轻松使用克隆方法。这样,您从ComType = 2返回相同的值,但不是同一个对象:

将克隆方法添加到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

当然这不是最佳代码。它只是向你展示这件事是如何运作的:)