Странное поведение двоичной сериализации .NET в словаре <Key, Value> - PullRequest
16 голосов
/ 19 января 2009

Я столкнулся, по крайней мере с моими ожиданиями, со странным поведением в двоичной сериализации .NET.

Все элементы Dictionary, которые загружены, добавляются к их родителям ПОСЛЕ обратного вызова OnDeserialization. В отличие от List делает по-другому. Это может сильно раздражать в реальном коде репозитория, например, когда вам нужно добавить несколько делегатов в элементы словаря. Пожалуйста, проверьте пример кода и посмотрите подтверждения.

Это нормальное поведение?

[Serializable]
public class Data : IDeserializationCallback
{
    public List<string> List { get; set; }

    public Dictionary<string, string> Dictionary { get; set; }

    public Data()
    {
        Dictionary = new Dictionary<string, string> { { "hello", "hello" }, { "CU", "CU" } };
        List = new List<string> { "hello", "CU" };
    }

    public static Data Load(string filename)
    {
        using (Stream stream = File.OpenRead(filename))
        {
            Data result = (Data)new BinaryFormatter().Deserialize(stream);
            TestsLengthsOfDataStructures(result);

            return result;
        }
    }

    public void Save(string fileName)
    {
        using (Stream stream = File.Create(fileName))
        {
            new BinaryFormatter().Serialize(stream, this);
        }
    }

    public void OnDeserialization(object sender)
    {
        TestsLengthsOfDataStructures(this);
    }

    private static void TestsLengthsOfDataStructures(Data data)
    {
        Debug.Assert(data.List.Count == 2, "List");
        Debug.Assert(data.Dictionary.Count == 2, "Dictionary");
    }
}

Ответы [ 3 ]

10 голосов
/ 19 января 2009

Да, вы обнаружили раздражающую причуду в десериализации Dictionary<TKey, TValue>. Вы можете обойти это, вручную вызывая метод словаря OnDeserialization():

public void OnDeserialization(object sender)
{
    Dictionary.OnDeserialization(this);
    TestsLengthsOfDataStructures(this);
}

Кстати, вы также можете использовать атрибут [OnDeserialized] вместо IDeserializationCallback:

[OnDeserialized]
public void OnDeserialization(StreamingContext context)
{
    Dictionary.OnDeserialization(this);
    TestsLengthsOfDataStructures(this);
}
8 голосов
/ 19 января 2009

Я могу воспроизвести проблему. Заглянул в Google и нашел: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94265, хотя я не уверен, что это та же самая проблема, похоже, она очень похожа.

EDIT:

Я думаю, что добавление этого кода могло решить проблему?

    public void OnDeserialization(object sender)
    {
            this.Dictionary.OnDeserialization(sender);
    }

Нет времени для исчерпывающего тестирования, и я хочу опередить Марка в ответ; -)

4 голосов
/ 19 января 2009

Интересно ... для информации, я попробовал это с подходом, основанным на атрибутах (ниже), и он ведет себя так же ... очень любопытно! Я не могу это объяснить - я просто отвечаю, чтобы подтвердить воспроизведенное и упомянуть поведение [OnDeserialized]:

[OnDeserialized] // note still not added yet...
private void OnDeserialized(StreamingContext context) {...}

Редактировать - найдена проблема "подключения" здесь . Попробуйте добавить к вашему обратному вызову:

Dictionary.OnDeserialization(this);
...