Как сериализовать объекты, созданные фабриками - PullRequest
9 голосов
/ 16 марта 2012

Я работаю над проектом, который использует внедрение зависимостей через Ninject.Пока что это работает очень хорошо, и мне очень нравится DI, но теперь я решил, что мне нужно сериализовать некоторые объекты, и мне трудно это делать, следуя шаблонам DI.

* 1002Скажем, у меня есть класс с именем Foo, у которого есть список баров, и он проходит через фабрику, например:
public class Foo
{
    private List<Bar> _bars;
    private BarFactory _barFactory;

    ...

    public void MakeBar()
    {
         _bars.Add(_barFactory.MakeBar());
    }
}

Вот бар, который создается при вызове _barFactory.MakeBar().Я хочу, чтобы Bar был сериализуемым:

public class Bar : ISerializable
{
    private List<IPickle> _pickles;
    private PickleFactory _pickleFactory;

    public Bar(PickleFactory factory)
    {
         _pickleFactory = factory;
    }

    public void MakePickle(int x)
    {
         _pickles.Add(_pickleFactory.MakePickle(x));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        //serialize member variables here
    }

    //Constructor called during deserialization
    private Bar(SerializationInfo info, StreamingContext context)
    {
        //fill in member variables with data from SerializationInfo
    }
}

Обратите внимание, что у Bar есть собственная фабрика и коллекция солений.Вот проблема: когда вызывается конструктор десериализации Bar, у меня нет никакого способа получить еще одну PickleFactory.Оригинальный PickleFactory был передан Bar Bar BarFactory, но BarFactory не вызывал конструктор десериализации.

Мой текущий план для решения этой проблемы - извлечь все сериализуемые члены Bar в его собственный класс, называемыйBarDataObject.Тогда я бы сделал сериализуемый BarDataObject, но не сам Bar.Я бы добавил в BarFactory функцию, которая принимает BarDataObject в качестве параметра и строит для вас Bar, заполненный всей информацией из BarDataObject.

Однако предположим, что Pickle также имеет классы обслуживаниякоторый он получил от фабрики, которая сделала это, который также не может быть сериализован.Таким образом, я должен был бы извлечь DataObject из Pickle, а мой BarDataObject должен был бы держать PickleDataObject.И предположим, что у Пикла тоже была переменная-член с набором данных и сервисов?Я должен был бы создать и поддерживать DataObject для этого.Это похоже на настоящий облом, особенно учитывая, что в моем проекте есть много других вещей, которые мне нужно сериализовать, и они, вероятно, столкнутся с той же проблемой.

Так есть ли лучшее решение?Я делаю что-то не так, DI-мудрый?Я только начал работать с DI и Ninject, но я не могу найти никого, кто придумал бы хороший способ сериализации объектов, которым были добавлены классы обслуживания.

1 Ответ

9 голосов
/ 16 марта 2012

По моему опыту, только классы обслуживания должны иметь зависимости, а классы обслуживания никогда не должны подвергаться сериализации.

Тот факт, что у вас есть класс, который вы хотите сериализовать, но который опирается на внедренный сервискажется мне запахом кода.

Трудно точно сказать, что вы пытаетесь достичь с помощью Bar, но из того, что я вижу, я бы предложил сделать Pickle POCOи используя List<Pickle> вместо пользовательского Bar класса.

Или, если Bar предназначен для получения другой сериализуемой информации, кроме Pickles, сделайте Bar POCO со свойством Pickles:

public class Bar
{
    public string Name {get;set;}
    public List<Pickle> Pickles {get;set;}
}

Поскольку POCO не будут иметь зависимостей, они не должны требовать фабрики, поэтому этот класс должен быть полностью сериализуемым.Если есть сложные функции, которые вы хотели бы выполнять в Bar s и Pickle s, их следует абстрагировать в отдельные служебные службы, которые принимают Bar s и Pickle s в качестве параметров их методов.

...