2012-03-15 17 views
8

Sto lavorando a un progetto che utilizza l'integrazione delle dipendenze tramite Ninject. Finora, sta funzionando molto bene, e sto piacendo molto a DI, ma ora ho deciso che ho bisogno di serializzare alcuni oggetti, e trovo difficile farlo seguendo i modelli DI.Come serializzare gli oggetti creati dalle fabbriche

Dire che ho una classe chiamata Foo, che ha una lista di bar, e li rende attraverso una fabbrica, come questo:

public class Foo 
{ 
    private List<Bar> _bars; 
    private BarFactory _barFactory; 

    ... 

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

Ecco Bar, che viene fatta quando _barFactory.MakeBar() viene chiamato. Voglio che la barra sia serializzabile:

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 
    } 
} 

Si noti che Bar ha una propria fabbrica e una raccolta di sottaceti. Ecco il problema: quando viene chiamato il costruttore di deserializzazione di Bar, non ho modo di procurarmene un'altra PickleFactory. Il PickleFactory originale è stato dato a Bar dal BarFactory, ma il costruttore di deserializzazione non è stato chiamato da BarFactory.

Il mio piano corrente per risolvere questo problema sarebbe quello di estrarre tutti i membri serializzabili di Bar nella propria classe denominata BarDataObject. Quindi renderei serializzabile BarDataObject, ma non Bar stesso. Aggiungerei una funzione a BarFactory che accetta un oggetto BarDataObject come parametro e crea una barra per te completata con tutte le informazioni da BarDataObject.

Tuttavia, supporre Pickle anche ha classi di servizio che ha ottenuto dalla fabbrica che lo ha prodotto, che non può essere serializzato. Quindi dovrei estrarre un DataObject da Pickle, e il mio oggetto BarDataObject dovrebbe rimanere su PickleDataObject. E supponi che Pickle avesse una variabile membro con un mix di dati e servizi anche tu? Dovrei creare e mantenere un DataObject anche per quello. Questo mi sembra un vero peccato, specialmente considerando che il mio progetto ha molte altre cose che devo serializzare e probabilmente si troveranno ad affrontare lo stesso problema.

Quindi c'è una soluzione migliore? Sto facendo qualcosa di sbagliato, DI-saggio? Ho appena iniziato a lavorare con DI e Ninject, ma non riesco a trovare nessuno che abbia trovato un buon modo per serializzare oggetti che sono stati iniettati con classi di servizio.

+0

È possibile aggiungere un costruttore alla classe 'BarFactory' che accetta le informazioni sulla serializzazione? – Matthew

+3

Che tipo di oggetto è Foo? È un "nuovo" o un "iniettabile"? (Http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/). –

+0

@Matthew: se lo facessi, come potrei ottenere SerializationInfo in fabbrica? Nel momento in cui è stato chiamato il costruttore privato di Bar, è troppo tardi per chiedere alla fabbrica di realizzare la barra, dato che siamo già nel costruttore di Bar e in ogni caso Bar non sa di BarFactory. – tandersen

risposta

9

Nella mia esperienza, solo le classi di servizio dovrebbero avere dipendenze e le classi di servizio non dovrebbero mai essere soggette a serializzazione.

Il fatto che si disponga di una classe che si desidera serializzare, ma che si basa su un servizio iniettato, mi sembra un odore di codice.

E 'difficile dire esattamente quello che stai cercando di realizzare con Bar, ma da quello che posso vedere, io suggerirei di fare Pickle essere un POCO, e utilizzando un List<Pickle> invece di una Bar classe personalizzata.

Oppure, se Bar è destinato ad avere altre informazioni serializzabile oltre al Pickles, fare Bar un POCO con una proprietà Pickles:

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

Perché pocos non avrà le dipendenze, che non dovrebbero richiedere fabbriche, quindi questa classe dovrebbe essere interamente serializzabile. Se ci sono funzioni complesse che si desidera eseguire su Bar s e Pickle s, devono essere estrapolate in servizi di utilità separati che prendono Bar se Pickle s come parametri del metodo.

+0

Concordo con StripingWarrior: è necessario separare i dati e il comportamento. – Steven

+0

Grazie per la risposta, sembra che potrebbe funzionare per il mio problema immediato. Fondamentalmente, stai suggerendo di prendere tutti i servizi da Bar e Pickle, e invece di parlare con Foo a quei servizi (come le fabbriche)? Belle. Ma se poi dovessi anche serializzare Foo? Creo anche Foo a POCO e trasferisco tutti i servizi di Foos, Bars e Pickles nel tipo che ha creato Foo? Non finirà per sfociare in una brutta classe che ha troppe responsabilità? – tandersen

+1

@tandersen: Sembra che tu capisca il principio. È la stessa strategia suggerita nell'articolo che Mark Seeman ha collegato nel suo commento. (Mark ha scritto letteralmente il libro su DI in. NET, tra l'altro). Penso che troverai abbastanza facile separare le responsabilità e mantenere le dimensioni delle classi piccole se segui questo schema. In caso contrario, sentiti libero di pubblicare una nuova domanda e vedere se la comunità SO può indicare alcuni modelli utili per il tuo caso particolare. – StriplingWarrior

Problemi correlati