反序列化时不创建具有 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 Interface and its OnDeserialization()方法
- 将 <OnDeserializing> or <OnDeserialized> 属性添加到 class 方法 (
internal
(friend
)/protected
)
实施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)
使用 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 Interface and its OnDeserialization()方法
- 将 <OnDeserializing> or <OnDeserialized> 属性添加到 class 方法 (
internal
(friend
)/protected
)
实施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)