События, не работающие после десериализации - PullRequest
1 голос
/ 28 сентября 2010

ПРОБЛЕМА:

У меня есть дочерний класс, который использует DataContractSerialization и вызывает событие Changed, когда установлено его свойство Name.

<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

Он содержится в родительском классе, который также использует DataContractSerialization и обрабатывает событие 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

Родительский класс сериализуется и десериализуется, и все данные (включая Дочерний) сохраняются и восстанавливаются, как и ожидалось.

Однако после десериализации событие Changed никогда не возникает!

ВОПРОСЫ:

Я знаю, что процесс десериализации обходит конструкторы классов, но разве событие не должно инициализироваться?

Я что-то не так делаю?

Можно ли сериализовать / десериализовать событие?

Есть ли лучший обходной путь, чем следующий (см. Ниже)?

Есть ли способ инициализировать событие в методе OnDeserialzed для Child, а не для Parent (см. Ниже)?

Временное решение:

(1) Добавить конструктор к классу Child, который в качестве аргумента принимает экземпляр себя.

(2) Добавьте метод OnDeserialized к классу Parent, который создает экземпляр New класса Child на основе десериализованного экземпляра класса Child.

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

    Child = New Child(Child)

End Sub

Теперь событие Changed вызывается, как и ожидалось.

1 Ответ

6 голосов
/ 28 сентября 2010

Проблема не в том, что событие Changed не запускается;если для десериализованного объекта используется то же самое определение класса (с установщиком, который вызывает событие) (с сериализацией DataContract, которая не является обязательной), событие будет инициировано.Происходит следующее: десериализованный объект больше не имеет подключенного обработчика.

Вы не можете сериализовать или десериализовать обработчики событий;по крайней мере, вы не должны.Поскольку они могут указывать на ссылки, отличные от текущей ссылки на объект, и поскольку десериализованный объект является новой ссылкой в ​​том, что, вероятно, отличается от времени выполнения, ссылки на обработчики событий из сериализованного объекта бесполезны при десериализации, поскольку ссылка больше не будет указыватьожидаемый объект в куче новой среды выполнения.

Решение немного проще, чем ваш обходной путь, но основано на той же идее;реализовать пользовательское поведение десериализации в родительском объекте, который повторно привязывает обработчик к событию потомка:

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

    AddHandler Child.Changed AddressOf Me.Child_Changed

End Sub

Это позволяет избежать затрат памяти и времени на создание экземпляра нового потомка, просто чтобы уничтожить другого, и должен выполнить тот же прием.Технически возможно сделать это для Ребенка, но Ребенку потребуется знание его Родителя с использованием обратной ссылки.Это также немного назад;Вообще говоря, сборщики событий не «захватывают» обработчики событий, а вместо этого передаются им другими объектами, которые содержат или знают об обработчиках и событии.

...