Проблема сериализации в .NET со ссылкой на статическое поле - PullRequest
1 голос
/ 21 мая 2009

Я использую SerializableAttribute для записи объекта jack на диск. Объект имеет член department, который ссылается на статическое поле accounts другого класса Department. При десериализации я обнаружил, что член department десериализованного объекта больше не указывает на тот же объект, что и статическое поле accounts, но теперь указывает на другую идентичную копию.

Все участвующие классы и объекты являются ссылочными типами. Как мне обойти это?

(Извините за длинный код сообщения).

#include "stdafx.h"

using namespace System;
using namespace System::IO;
using namespace System::Runtime::Serialization;
using namespace System::Runtime::Serialization::Formatters::Binary;

[Serializable]
ref class Department {
    static Department(){ accounts = gcnew Department(L"Accounts"); }
public:
    static Department ^accounts;
    // similarly other departments come here...

    String ^name;
    Department(String ^name) : name(name) { }
};

[Serializable]
ref class Employee {
public:
    String ^name;
    Department ^department;

    Employee(String ^name, Department ^department) : name(name),
        department(department) { }

};

int main(array<System::String ^> ^args)
{
    Employee ^jack;
    IFormatter ^formatter = gcnew BinaryFormatter();

    String ^option = Console::ReadLine();
    if(option == L"read"){
        Stream ^stream = gcnew FileStream(L"dingdong.bin", FileMode::Open,
            FileAccess::Read, FileShare::Read);
        jack = (Employee^) formatter->Deserialize(stream);

        if(jack->department != Department::accounts)
            Console::WriteLine(L"Different objects");
        else
            Console::WriteLine(L"The same object");
        stream->Close();
        Console::ReadLine();
    }
    else {
        jack = gcnew Employee(L"Jack", Department::accounts);
        Stream ^stream = gcnew FileStream(L"dingdong.bin", FileMode::Create,
            FileAccess::Write, FileShare::None);
        formatter->Serialize(stream, jack);
        stream->Close();
    }

    return 0;
}

Редактировать: Добавлен пример кода

Ответы [ 3 ]

2 голосов
/ 21 мая 2009

В простейшем случае, [NonSerialized] с IDeserializationCallback для восстановления ссылки поможет. Вместо этого вы можете сериализовать код отдела. Как правило, если вам нужно сериализовать такие синглтоноподобные объекты, вы можете сериализовать ссылающийся объект вручную и заменить «ссылочный» объект , который реализует IObjectReference, или, возможно, использовать суррогаты сериализации вместо ручной сериализации для замены «ссылочного» объекта.

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

1 голос
/ 21 мая 2009

Я так не думаю. При сериализации - сериализованная копия текущего значения статического поля f. Когда это десериализуется, создается объект соответствующего типа и его значения гидратируются из сериализованных данных. Это могут быть ссылочные типы, но сериализация - это передача значений объектов между A и B, а не их ссылок.

Вы сохраняете на диск. Откуда вы знаете, что f и его статическое поле все еще будут находиться в области видимости при загрузке с диска и десериализации?

0 голосов
/ 21 мая 2009

Если вы посмотрите документацию по атрибутам [NonSerialized], я думаю, вы найдете этот пример там.


Хорошо, теперь, когда вы разместили код, проблема становится более понятной. Вы должны выделить статическую часть класса Department в класс Departments. Список или перечень отделов не имеет ничего общего с отдельными объектами Отдела.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...