Events not working with after Deserialization

守給你的承諾、 提交于 2019-12-20 04:49:56

问题


PROBLEM:

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

<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.

<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.

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

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)?

WORKAROUND:

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

(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.

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

    Child = New Child(Child)

End Sub

Now the Changed event is raised as expected.


回答1:


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.

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.



来源:https://stackoverflow.com/questions/3807465/events-not-working-with-after-deserialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!