反序列化时不创建具有 NonSerialized 属性的对象

Objects having NonSerialized attribute are not created when deserializing

使用 BinaryFormatter class:

<Serializable>
Class Class1
    Public Property List1 as New List(Of Something)

    <NonSerialized> 
    Public Property List2 as New List(Of Something)
End Class

当我序列化一个像这样的对象然后反序列化它时,List2 将被设置为 Nothing

正确的处理方法是什么?
我不希望 List2 被序列化,但是当我反序列化 class 时我确实希望它是一个空列表。

BinaryFormatter 不调用 class 构造函数,也不以任何方式初始化 class 对象:相反,它在内存中创建未初始化的对象。
您可以在 .Net 源代码中看到这一点:当 ParseObject() method is called, the class Object is generated by the GetUninitializedObject(Type type) 方法时。
下一个调用是 [MethodImpl] 函数,nativeGetUninitializedObject((RuntimeType)type),所以我们必须在这里停下来,但是已经很清楚发生了什么:返回的 Object 代表一个未初始化的类型,因此none 个非序列化字段已初始化,也未调用 class 构造函数。

如果您实际上不需要使用 BinaryFormatter class、Json.Net serializer/deserializer does initialize a class object instance when deserializing the type. It also respects the <NonSerialized> 属性。如果您决定使用它,则无需修改 class 对象定义。

如果您必须使用 BinaryFormatter,您有两个选择:


实施IDeserializationCallback:

<NonSerialized>适用于字段:List2自动属性改为实例字段(属性版本在下一个例子中保留):

<Serializable>
Class Class1
    Implements IDeserializationCallback

    <NonSerialized>
    Public List2 As List(Of Integer) = New List(Of Integer)()

    Public Property List1 As New List(Of String)

    Public Sub OnDeserialization(sender As Object) Implements IDeserializationCallback.OnDeserialization
        List2 = New List(Of Integer)
    End Sub
End Class

使用 <OnDeserializing> 属性:

<OnDeserializing>属性添加到方法时,我们不需要实现IDeserializationCallback接口。

此处,Class 类型添加了一个带有支持字段的新标准 属性。
<NonSerialized> 属性应用于 List3 的支持字段:
(请注意,[field: NonSerialized] 属性已添加到 c# 7.3 中的属性)

<Serializable>
Class Class1

    <NonSerialized>
    Public List2 As List(Of Integer) = Nothing

    <NonSerialized>
    Private m_List3 As List(Of Double)

    Public Sub New()
        List2 = New List(Of Integer)
    End Sub

    Public Property List1 As New List(Of String)

    Public Property List3 As List(Of Double)
        Get
            Return m_List3
        End Get
        Set
            m_List3 = Value
        End Set
    End Property

    <OnDeserializing()>
    Friend Sub OnDeserialization(ByVal context As StreamingContext)
        List2 = New List(Of Integer)()
        m_List3 = New List(Of Double)()
    End Sub
End Class

在这两种情况下,BinaryFormatter 的 Deserialize() 方法将重新创建序列化的 class 对象,其中包含已初始化但为空的非序列化列表:

Dim formatter = New BinaryFormatter()

Dim cls1 = New Class1() With {
    .List1 = New List(Of String) From {"1", "2", "3"},
    .List2 = New List(Of Integer) From {4, 5, 6}
}

Using writer = New FileStream(Path.Combine(AppContext.BaseDirectory(), 
    "Class1Serialized.bin"), FileMode.Create, FileAccess.Write)
    formatter.Serialize(writer, cls1)
End Using

Dim cls1Deserialized As Class1 = Nothing
Using reader = New FileStream(Path.Combine(AppContext.BaseDirectory(), 
    "Class1Serialized.bin"), FileMode.Open, FileAccess.Read)
    cls1Deserialized = TryCast(formatter.Deserialize(reader), Class1)
End Using

使用NewtonSoft.Json:

Dim cls1 As New Class1() With {
    .List1 = New List(Of String) From {"1", "2", "3"},
    .List2 = New List(Of Integer) From {4, 5, 6}
}

' Serialize
Dim class1Json = JsonConvert.SerializeObject(cls1)
' [...]
' Deserialize
Dim cls1b = JsonConvert.DeserializeObject(Of Class1)(class1Json)