反序列化后无法使用的事件

时间:2022-11-03 00:04:55

PROBLEM:

问题:

I have a Child class which uses DataContractSerialization and raises a Changed event when its Name property is set.

我有一个使用DataContractSerialization的Child类,并在设置Name属性时引发Changed事件。

<DataContract()>
Public Class Child

    Public Event Changed()

    <DataMember()>
    Private _Name As String

    Public Sub New(ByVal NewName As String)
        _Name = NewName
    End Sub

    Public Property Name() As String
        Get
            Return _Name
        End Get
        Set(ByVal value As String)
            _Name = value
            RaiseEvent Changed()
        End Set
    End Property

End Class

It is contained within a Parent class which also uses DataContractSerialization and handles the Changed event of the Child.

它包含在Parent类中,该类也使用DataContractSerialization并处理Child的Changed事件。

<DataContract()>
Public Class Parent

    <DataMember()>
    Private WithEvents Child As Child

    Private Sub Child_Changed() Handles Child.Changed

        'Handle changed event here...

    End Sub

End Class

The Parent class is serialzed and deserialized and all the data (including the Child) is saved and resored as expected.

Parent类被序列化和反序列化,所有数据(包括Child)都按预期保存和恢复。

However, after deserialization, the Changed event is never raised!

但是,在反序列化之后,永远不会引发Changed事件!

QUESTIONS:

问题:

I know the deserialization process bypasses class constructors, but shouldn't the event be initialized?

我知道反序列化过程会绕过类构造函数,但是不应该初始化事件吗?

Am I doing something wrong?

难道我做错了什么?

Is it possible to serialize/deserialize the Event?

是否可以序列化/反序列化事件?

Is there a better workaround than the following (see below)?

有没有比以下更好的解决方法(见下文)?

Is there a way to initialize the event in the OnDeserialzed method of the Child rather than the Parent (see below)?

有没有办法在Child的OnDeserialzed方法而不是Parent中初始化事件(见下文)?

WORKAROUND:

解决方法:

(1) Add a constructor to the Child class which takes an instance of itself as an argument.

(1)向Child类添加一个构造函数,该类将自身的实例作为参数。

(2) Add an OnDeserialized method to the Parent class which creates a New instance of the Child class based on the deserialzed instance of the Child class.

(2)将一个OnDeserialized方法添加到Parent类,该类根据Child类的反序列化实例创建Child类的New实例。

<OnDeserialized()>
Private Sub OnDeserializedMethod(ByVal Context As StreamingContext)

    Child = New Child(Child)

End Sub

Now the Changed event is raised as expected.

现在,Changed事件按预期引发。

1 个解决方案

#1


5  

The problem is not that the Changed event isn't being fired; as long as the same class definition (with the setter that raises the event) is used for the deserialized object (with DataContract serialization that isn't a requisite), the event will be raised. What's happening is that the deserialized object no longer has the handler attached.

问题不在于Changed事件没有被触发;只要将相同的类定义(使用引发事件的setter)用于反序列化的对象(使用不是必需的DataContract序列化),就会引发该事件。发生的事情是反序列化的对象不再附加处理程序。

You cannot serialize or deserialize event handlers; at the very least, you shouldn't. Because they may point to references other than the current object reference, and because the deserialized object is a new reference in what is probably a different runtime, event handler references from the serialized object are useless on deserialization, because the reference will no longer point to the expected object in the new runtime's heap.

您无法序列化或反序列化事件处理程序;至少,你不应该。因为它们可能指向除当前对象引用之外的引用,并且因为反序列化对象是可能是不同运行时的新引用,所以来自序列化对象的事件处理程序引用在反序列化时是无用的,因为引用将不再指向新运行时堆中的预期对象。

The solution is a little easier than your workaround, but based on the same idea; implement custom deserialization behavior in the parent that reattaches the handler to the child's event:

解决方案比您的解决方案更容易,但基于相同的想法;在父级中实现自定义反序列化行为,将处理程序重新附加到子事件:

<OnDeserialized()>
Private Sub OnDeserializedMethod(ByVal Context As StreamingContext)

    AddHandler Child.Changed AddressOf Me.Child_Changed

End Sub

This avoids the memory and time costs of instantiating a new Child just to destroy another one, and should do the same trick. It is technically possible to do this on the Child, but the Child would require knowledge of its Parent using a backreference. It's also a little backwards; generally speaking, event raisers don't "grab" event handlers, but instead are given them by other objects that contain or know about the handlers and the event.

这样可以避免实例化一个新Child的内存和时间成本,只是为了销毁另一个,并且应该做同样的技巧。技术上可以在Child上执行此操作,但Child需要使用反向引用来了解其Parent。它也有点倒退;一般来说,事件提升者不会“抓取”事件处理程序,而是由包含或了解处理程序和事件的其他对象提供。

#1


5  

The problem is not that the Changed event isn't being fired; as long as the same class definition (with the setter that raises the event) is used for the deserialized object (with DataContract serialization that isn't a requisite), the event will be raised. What's happening is that the deserialized object no longer has the handler attached.

问题不在于Changed事件没有被触发;只要将相同的类定义(使用引发事件的setter)用于反序列化的对象(使用不是必需的DataContract序列化),就会引发该事件。发生的事情是反序列化的对象不再附加处理程序。

You cannot serialize or deserialize event handlers; at the very least, you shouldn't. Because they may point to references other than the current object reference, and because the deserialized object is a new reference in what is probably a different runtime, event handler references from the serialized object are useless on deserialization, because the reference will no longer point to the expected object in the new runtime's heap.

您无法序列化或反序列化事件处理程序;至少,你不应该。因为它们可能指向除当前对象引用之外的引用,并且因为反序列化对象是可能是不同运行时的新引用,所以来自序列化对象的事件处理程序引用在反序列化时是无用的,因为引用将不再指向新运行时堆中的预期对象。

The solution is a little easier than your workaround, but based on the same idea; implement custom deserialization behavior in the parent that reattaches the handler to the child's event:

解决方案比您的解决方案更容易,但基于相同的想法;在父级中实现自定义反序列化行为,将处理程序重新附加到子事件:

<OnDeserialized()>
Private Sub OnDeserializedMethod(ByVal Context As StreamingContext)

    AddHandler Child.Changed AddressOf Me.Child_Changed

End Sub

This avoids the memory and time costs of instantiating a new Child just to destroy another one, and should do the same trick. It is technically possible to do this on the Child, but the Child would require knowledge of its Parent using a backreference. It's also a little backwards; generally speaking, event raisers don't "grab" event handlers, but instead are given them by other objects that contain or know about the handlers and the event.

这样可以避免实例化一个新Child的内存和时间成本,只是为了销毁另一个,并且应该做同样的技巧。技术上可以在Child上执行此操作,但Child需要使用反向引用来了解其Parent。它也有点倒退;一般来说,事件提升者不会“抓取”事件处理程序,而是由包含或了解处理程序和事件的其他对象提供。