Сериализация и десериализация, когда ссылки задействованы в C # - PullRequest
3 голосов
/ 01 июля 2011

У меня есть одноэлементный класс Manager, который содержит список экземпляров объекта:

static class Manager
{
    static List<Foo> Foos = new List<Foo>();
}

Затем у меня есть коллекция экземпляров объекта, использующая класс Meter, который использует ссылки на элементы в списке Foos:

class Meter
{
    public Foo MyFoo = null;
}

...

public void CreateMeter(int UserChoice)
{
    Meter MyMeter = new Meter();
    MyMeter.MyFoo = Manager.Foos[UserChoice];
}

Когда приложение сохраняет файл проекта, оно сериализует экземпляры Foo в Foos вместе со всеми экземплярами Meter.

Моя проблема заключается в том, как десериализовать это соглашение.В настоящее время я делаю следующее:

  • Десериализация экземпляров Foo для всего проекта для реконструкции Manager.Foos
  • Десериализация экземпляра счетчика, который включает в себя экземпляр Foo для свойства MyFoo
  • Search Manager.Foos и найдите соответствующую ссылку для MyMeter.MyFoo, а затем назначьте ссылку из Manager.Foos.

Это кажется мне неуклюжим и его не так просто расширить.Я бы предпочел, чтобы фабрика Meter не нуждалась в поиске Manager.Foos во время десериализации, потому что в будущем Meter может отнести его к экземпляру Foo из других мест, а не только из Manager.

Есть ли простой, но гибкийальтернативное решение этой проблемы десериализации, где ссылки на объекты могут быть легко восстановлены?

Ответы [ 3 ]

4 голосов
/ 01 июля 2011

Сериализация трудна:)

Делать это автоматически, не мешая форматированию, - боль.Обычный трюк здесь заключается в назначении несвязанного непрозрачного ключа при де / сериализации с использованием центральной карты.Вы можете увидеть это в DataContractSerializer, включив отслеживание ссылок в конструкторе.Этот ключ затем используется для проверки существующих объектов в качестве заменителя.

Лично, когда он получает такой сложный ИМО, пора использовать предварительно консервированный антенна;Даже внутри выделенной библиотеки это немного сложно.Подход, который я использую (protobuf-net), довольно похож, но сложнее для чтения (двоичный плотный вывод и т. Д.).

0 голосов
/ 01 июля 2011

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

Foo определяет свойство Guid, которое содержит уникальный Guid. Это создается в конструкторе, но также может быть сохранено / восстановлено с помощью сериализации / десериализации.

class Foo
{
    public Guid TheGuid = Guid.NewGuid();
}

Метр больше не использует ссылку, вместо этого он использует Guid:

class Meter
{
    public Guid FooGuid;
}

Когда счетчик создан, Guid устанавливает соединение:

public void CreateMeter(int UserChoice)
{
    Meter MyMeter = new Meter();
    MyMeter.FooGuid = Manager.Foos[UserChoice].TheGuid;
}

Когда счетчик сериализуется / десериализуется, Guid сохраняется / загружается.

Единственный недостаток - доступ к экземпляру Foo, связанному со счетчиком. Вместо непосредственного использования ссылки необходимо выполнить поиск, который повлечет за собой снижение производительности:

class Manager
{
    public List<Foo> Foos = new List<Foo>();

    public Foo GetFooFromGuid(Guid SearchGuid)
    {
        // search Foos and return instance with Guid == SearchGuid
    }
}

Преимущество этого подхода заключается в том, что теперь я могу создать делегата и иметь несколько источников Foo для связи со счетчиками:

Func<Guid, Foo> FooSource;

FooSource ManagerFooSource = Manager.GetFooFromGuid;
0 голосов
/ 01 июля 2011

в классе менеджера add

public static ulong IdProvider=0

в классе Foo add

public ulong MyId

в Foo ctor add

MyId=Manager.IdProvider++;

каждый класс Foo будет иметь уникальный идентификатор (до 2 ^ 64-1 экземпляров), просто сохраните IdProvider, чтобы вы могли продолжать добавлять уникальные идентификаторы при реконструкции.

Возможно, вы захотите изменить класс Meter для хранения уникального идентификатора Foo и предоставить свойство (get; set) для ссылки на «Foos» в классе Manager.

Я не совсем понял, что выхочу, но с этой точки зрения вы сделали беспорядок: p

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