2009-05-07 2 views
12

Ho bisogno di salvare alcune classi e strutture dati in un file. Il mio primo riflesso è stato usare la serializzazione XML o binario, ma questo si sta trasformando in un incubo. Ho un insieme di classi che non sono state pensate per essere serializzate (setter privati, nessun costrutto senza parametri, nessun attributo di serializzazione, dizionari, ecc.). Considerando che non posso cambiare quelle classi, cosa dovrei fare? C'è qualche soluzione e continua a usare la serializzazione?Come serializzare le classi che non sono state progettate per essere serializzate?

Devo scrivere tutto il codice per scrivere proprietà, collezioni, ecc.?

+0

buona domanda, puoi approfondire i requisiti di prestazioni e la portata del problema in questione. –

+0

A questo punto, non ho alcun requisito. Sto cercando la soluzione più elegante. – Martin

+1

non puoi davvero progettare una soluzione a un problema con zero requisiti :) indipendentemente dalla soluzione scelta, è probabile che sia la soluzione sbagliata. Non c'è davvero modo di rispondere a questa domanda se non ci sono requisiti ... –

risposta

9

Utilizzare JavaScriptSerializer. Si trova nello spazio dei nomi System.Web.Script.Serialization ed è implementato nel framework 3.5 nell'assembly System.Web.Extensions.dll.

Con questa classe, è possibile serializzare qualsiasi POCO, indipendentemente dal fatto che sia contrassegnato come [Serializzabile] o meno. Il tuo programma non deve essere un'applicazione web per utilizzare la serializzazione JSON.Ecco un esempio:

public class Unserializable 
{ 
    public int Age { get; set; } 
    public int ID { get; set; } 
    public string Name { get; set; } 
} 

public class Program 
{ 
    static void Main() 
    { 
    var u = new Unserializable 
      { 
       Age = 40, 
       ID = 2, 
       Name = "Betty" 
      }; 
    var jser = new JavaScriptSerializer(); 
    var jsonText = jser.Serialize(u); 
    // next line outputs {"Age":40,"ID":2,"Name":"Betty"} 
    Console.WriteLine(jsonText); 
    } 
} 
+0

+1 perché non lo sapevo. Gestisce anche i campi? –

+0

Sì, gestisce anche i campi. Prova questo: public class Unserializable { public int Età; ID int pubblico {get; impostato; } stringa pubblica Nome {get; impostato; } public Unserializable (int age, int id, string name) { Età = età; ID = id; Nome = nome; } } var u = new Unserializable (40, 2, "Donna"); var jser = new JavaScriptSerializer(); var jsonText = jser.Serialize (u); Console.WriteLine ("Serialized {0} using" + "JavaScriptSerializer in {1}:", u.GetType(). Name, jsonText); Questo produce testo JSON per l'oggetto che contiene il campo pubblico come '{"Età": 40, "ID": 2, "Nome": "Donna"}'. –

0

vorrei utilizzare uno strumento di generazione di codice (MyGeneration, T4, qualsiasi altra cosa) per generare le DTOS a puntate ...

+0

Il problema con il codice che ti fa uscire da questo è che se la classe cambia devi ricodificare il codice gen. Questo potrebbe o non potrebbe essere un problema. –

+0

Non vedo alcun motivo per -1 questo ... –

0

Non una semplice soluzione.

Probabilmente si desidera serializzare/deserializzare i campi (privati ​​e pubblici) nelle classi e farlo in modo ricorsivo. Probabilmente dovrai usare la riflessione per arrivare a loro. Non de/serializzare le proprietà, perché potrebbero esserci effetti collaterali quando si imposta un valore di proprietà. Dovrai anche de/serializzare ricorsivamente tutti i campi che sono Oggetti. La sfida è sapere dove fermarsi.

Dovrete fare alcune grosse ipotesi su come deserializzare un oggetto serializzato usando la riflessione. Devo supporre che alcuni dei campi di quegli oggetti contengano riferimenti ad altri oggetti, e tu dovresti sapere anche come attraversare tutto questo.

Inoltre, è necessario chiamare i costruttori parametrizzati e sperare che non si stia danneggiando troppo quando si impostano i campi con la riflessione.

In breve, potrebbe essere preferibile creare un set di classi wrapper per scopi speciali che faccia una forma ottimale per ricreare le classi proprietarie da un formato serializzato. Le tue classi di scopo speciale potrebbero quindi essere rese serializzabili. Questo non sarà un compito semplice.

Detto questo, il codice gen potrebbe essere in grado di semplificare il compito di identificare tutti i campi nelle classi.

0

Un'altra opzione consiste nell'utilizzare un modello di adattatore.

La buona notizia è che non sarà necessario modificare la classe originale. La cattiva notizia è che probabilmente finirai a scrivere il doppio del codice che esiste nella prima classe "immodificabile".

Finiremo con 2 nuove classi: l'adattatore e la nuova classe serializzabile.

L'idea è che l'adattatore sa come creare la classe serizile esaminando la classe non serializzabile. Per andare nella direzione opposta (serializzabile a non serializzabile) puoi ancora usare un adattatore (ovviamente, sto assumendo che i tuoi setter privati ​​siano effettivamente impostati tramite il costruttore parametrizzato).

Here's the pattern in detail.

0

Ci sono due parti distinte a questo:

  1. estrazione/impostazione dei dati
  2. memorizzazione/lettura da file (o un'altra posizione)

Per la prima parte, se non è possibile modificare le classi che si desidera serializzare/deserializzare, si è in realtà solo una copia profonda attraverso la riflessione.

Per la serializzazione, passare attraverso ciascun membro della classe che memorizza il suo valore.

Utilizzare quale media su cui si desidera archiviarlo, ad esempio XML, e scrivere questi valori su disco.

Per la deserializzazione, leggere i valori dal file, creare una nuova istanza dell'oggetto e utilizzare la riflessione per impostare tutti i valori.

Se si ottiene/imposta tutti i membri si avrà un oggetto che si trova in uno stato identico. (Potrebbe essere necessario ricorrere in modo ricorsivo a tutti gli oggetti se si hanno membri complessi.)

Per quanto riguarda il modo in cui si memorizzano i dati su disco, xml o binario funzionano entrambi. Se vuoi vederlo e renderlo leggibile dall'uomo, allora vai con XML. (Lo raccomando per la tua iniziale pugnalata perché renderà il debug molto più facile.)

7

Sembra un lavoro per ... surrogati di serializzazione!

Vai http://msdn.microsoft.com/en-us/magazine/cc188950.aspx

per una panoramica.

+0

+1: I surrogati giocheranno bene con BinaryFormatter. –

+0

Link dead, archive here: https://web.archive.org/web/20141231105711/http://msdn.microsoft.com/en-us/magazine/cc188950.aspx o MSDN: https: // msdn. microsoft.com/en-us/library/system.runtime.serialization.surrogateselector(v=vs.110).aspx –

0

Dipende davvero dalla scala del problema e dalle prestazioni necessarie.

Se si dispone di 1 classe problema, scriverei semplicemente una classe surrogata che può serializzare/deserializzare quella classe. Se parli di centinaia di classi, probabilmente devi usare un framework di serializzazione che supporti tutte le complessità. Nessuna costruzione senza parametri è un incubo, qualunque sia il framework di serializzazione che scrivi o usi dovrai conoscere in anticipo i parametri da passare al costruttore. Setter/dizionari/elenchi privati ​​ecc. Non sono un problema.

Ho scritto un framework mini-serialization per Media Browser che è BSD. La mia attenzione era rivolta alle prestazioni, ma le tecniche che uso possono essere adattate al tuo problema. Analogamente, potrebbero essere utilizzate le tecniche utilizzate in Marc's protocol buffers.

Se le prestazioni non sono affatto importanti, un framework di serializzazione abbastanza banale può essere codificato abbastanza rapidamente che utilizza la riflessione, la roba diventa difficile quando si tenta di mantenere la cosa performante.