不工作后反序列化活动序列化、工作

2023-09-06 23:22:09 作者:造福群众深藏功与名

问题:的

我有使用DataContractSerialization并提出当其名称属性设置一个Changed事件子类。

 < D​​ataContract()>
公共类儿童

    公共事件改变()

    <数据成员()>
    私人_Name作为字符串

    公共子新(BYVAL新名称作为字符串)
        _Name =新名称
    结束小组

    公共属性Name()作为字符串
        得到
            返回_Name
        最终获取
        设置(BYVAL值作为字符串)
            _Name =价值
            改变的RaiseEvent()
        结束设定
    高端物业

末级
 

据载也使用DataContractSerialization和处理儿童Changed事件一个父类中。

 < D​​ataContract()>
公共类父

    <数据成员()>
    私人WithEvents就儿童作为儿童

    私人小组Child_Changed()处理Child.Changed

        在这里处理更改事件...

    结束小组

末级
 

父类是serialzed和反序列化,所有的数据(包括儿童)被保存和resored预期。

但是,反序列化后,改变的事件从未提出!

问题:的

我知道反序列化进程绕过类的构造函数,但不应事件被初始化?

我是不是做错了什么?

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

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

有没有一种方法来初始化儿童OnDeserialzed方法,而不是家长的事件(见下文)?

解决方法:的

(1)添加一个构造函数类Child它接受自己的一个实例作为参数。

(2)添加OnDeserialized方法,它创建了子类的基础上,儿童类的deserialzed实例的新实例父类。

 < OnDeserialized()>
私人小组OnDeserializedMethod(BYVAL背景信息的StreamingContext)

    儿童=新的​​儿童(儿童)

结束小组
 
IM

现在改变的事件引发预期。

解决方案

现在的问题是不是已更改的事件不被解雇;只要相同的类的定义(以引发事件的设定器)被用于反序列化对象(与DataContract系列化这不是一个必要的),该事件将提高。这是怎么回事的是,反序列化对象不再有附加的处理程序。

您不能序列化和反序列化的事件处理程序;最起码,你不应该。因为他们可能指向引用比当前对象引用其他,并且因为反序列化对象是在什么可能是一个不同的运行时一个新的参考,从序列化的对象的事件处理程序的引用都在反序列化没用,因为参考将不再指向到在新的运行时的堆了预期目标。

解决的办法是比你的解决方法更容易一点,但基于同样的想法;在重新佩戴处理孩子的事件母公司实现自定义序列化的行为:

 < OnDeserialized()>
私人小组OnDeserializedMethod(BYVAL背景信息的StreamingContext)

    AddHandler的Child.Changed AddressOf Me.Child_Changed

结束小组
 

这可以避免实例化一个新的孩子只是要摧毁另一个的内存和时间成本,而且应该做同样的伎俩。这在技术上是可以做到这一点的孩子,但孩子就要使用反向引用要求其父母的知识。这也是一个有点倒退;一般来说,事件饲养员不抢事件处理程序,而是由包含或了解的处理程序和事件等对象给了他们。

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.

解决方案

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.