Странная ошибка десериализации, дочерние объекты не полностью десериализованы - PullRequest
3 голосов
/ 09 декабря 2011

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

[Serializable]
class Foo : ISerializable
{
    public Dictionary<int, string> Dict { get; private set; }

    public Foo()
    {
        Dict = new Dictionary<int, string>();
    }

    public Foo(SerializationInfo info, StreamingContext context)
    {
        Dict = (Dictionary<int, string>)info.GetValue("Dict", typeof(Dictionary<int, string>));
        Dict.Add(99, "test"); // Error here
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Dict", Dict);
    }

}

Вкл.В строке, где я добавляю данные в словарь, я получаю NullReferenceException, но свойство Dict не равно нулю: оно создается, но не инициализируется (все его поля равны 0 или нулю).Я подозреваю, что он был создан только с FormatterServices.GetUninitializedObject, но еще не десериализован.

Я понимаю, что на данный момент, возможно, не предполагается, что будет полностью инициализирован.Поэтому я попробовал другой подход, реализовав интерфейс IDeserializationCallback.MSDN говорит:

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

Если объект должен выполнить код на своих дочерних объектах, он может отложить это действие, реализовать IDeserializationCallback и выполнить код только при его повторном вызове на этом интерфейсе

Такпохоже, это именно то, что мне нужно, и я ожидал, что мой словарь будет полностью инициализирован при вызове OnDeserialization ... Но я получаю ту же ошибку!

[Serializable]
class Foo : IDeserializationCallback
{
    public Dictionary<int, string> Dict { get; private set; }

    public Foo()
    {
        Dict = new Dictionary<int, string>();
    }

    public void OnDeserialization(object sender)
    {
        Dict.Add(99, "test"); // Error here
    }
}

Так как IDeserializationCallbackпредназначенный для выполнения кода на дочерних объектах, я ожидал бы, что дочерние объекты будут полностью инициализированы на этом этапе.Обратите внимание, что если я вызываю OnDeserialize вручную в словаре, он работает нормально, но почему-то я не думаю, что должен это делать ...

Это поведение нормально?Кто-нибудь может объяснить, что здесь происходит?

Ответы [ 2 ]

1 голос
/ 11 декабря 2011

Если вы добавите Dict.OnDeserialization(sender) в свой обработчик десериализации, тогда все станет хорошо.

Итак, это работает:

    [Serializable]
    class Foo : IDeserializationCallback
    {
        public Dictionary<int, string> Dict { get; private set; }

        public Foo()
        {
            Dict = new Dictionary<int, string>();
        }

        public void OnDeserialization(object sender)
        {
            // The dictionary is initialized with values in next line
            Dict.OnDeserialization(sender);
            Dict.Add(99, "test");
        }
    }
0 голосов
/ 09 декабря 2011

Вам нужно создать экземпляр вашего словаря <> в обработчике OnDeserialization

public void OnDeserialization(object sender)
{
    Dict = new Dictionary<int, string>();
    Dict.Add(99, "test"); // Error here
}
...