2010-04-07 11 views
21

Ho bisogno di mantenere un oggetto che non è contrassegnato con l'attributo serializable. L'oggetto proviene da una libreria di terze parti che non posso modificare.Persistere un oggetto che non è contrassegnato come serializzabile

Ho bisogno di memorizzarlo in un posto fisso, come ad esempio il file system, quindi la soluzione ottimale sarebbe serializzare l'oggetto in un file, ma dal momento che non è contrassegnato come serializzabile, non è una scala soluzione avanzata.

È un oggetto piuttosto complesso, che contiene anche una raccolta di altri oggetti.

Avete qualche suggerimento su come risolvere questo problema? Il codice non verrà mai eseguito in un ambiente di produzione, quindi sto bene con quasi tutte le soluzioni e le prestazioni.

+12

Le ultime parole famose ... 'Il codice verrà mai eseguito in un'environment' produzione: oP –

+0

@ Matteo: Sì, giusto :-) +1 – driis

+0

Heh, lo so :) È solo per accelerare un po 'di tempo di riscaldamento durante lo sviluppo, quindi non ha molto senso da nessun'altra parte. – lasseeskildsen

risposta

9

XmlSerializer può essere un utile prima cosa da provare, i tipi sono pubblici, ecc.

Se ciò fallisce, v2 di protobuf-net (in corso, si dovrebbe d per costruire dal sorgente, ma posso aiutare) funziona con oggetti non attribuiti, quindi ideale per tipi al di fuori del tuo controllo - devi solo dirgli cosa includere (tramite DSL). Il codice v2 non è completo, ma copre gli scenari più comuni, comprese le raccolte ecc. (Il lavoro incompleto è principalmente callback ed enumerazioni).

+0

protobuf-net sembra molto carino. Richiede costruttori senza parametri? – lasseeskildsen

+0

@lasseeskildsen - al momento sì, sì - ma dal momento che lo possiedo sono sicuro di poter aggiungere l'approccio WCF (di non chiamare nessun ctor). Ci vorranno solo pochi istanti (è solo una chiamata a 'FormatterServices.GetUninitializedObject'). –

+0

Se si dispone di un esempio dell'API di terze parti, è possibile creare un esempio v2. –

2

Non so se è eccessivo per il vostro utilizzo, ma ho giocato ultimamente con db4o. Persisterà qualsiasi oggetto, basta chiamare IObjectContainer.Store (oggetto) ed è leggero e basato su file. Non richiede alcuna installazione.

Non ho ancora avuto problemi con esso.

3
+0

I collegamenti non funzionano più. Primo articolo: [link] (https: //web.archive.org/web/20101213020136/http: //www.codeproject.com/kb/dotnet/Surrogate_Serialization.aspx) Secondo articolo: [collegamento] (https://web.archive.org/web/20141231105711/http://msdn .microsoft.com/it/us/magazine/cc188950.aspx) – milosa

5

È possibile scrivere un metodo ricorsivo che esegua il grafico degli oggetti utilizzando il reflection per mantenere l'oggetto ... Riportarlo potrebbe essere molto più difficile. Chissà se qualcuno di questi oggetti contiene riferimenti a risorse non gestite o di sistema. Se dovessi fare qualcosa di pazzesco, sceglierei il metodo .GetFields(...) per il tipo.

Un'altra idea ...

Se sei solo facendo questo per accelerare lo sviluppo perché non avvolgere le loro clases con le proprie classi adattatore. Ciò ti consentirebbe di sostituire le librerie di terze parti con le tue classi di simulazione semplificate e di consentire migliori possibilità di sostituzione e riutilizzo in seguito.

Malato come è ... Questo è stato più facile di quanto pensassi. (Anche se questo funziona ... perche avvolgendo le classi terze parti.)

public static class Tools 
{ 
    public static XElement AsXml(this object input) 
    { 
     return input.AsXml(string.Empty); 
    } 
    public static XElement AsXml(this object input, string name) 
    { 
     if (string.IsNullOrEmpty(name)) 
      name = input.GetType().Name; 

     var xname = XmlConvert.EncodeName(name); 

     if (input == null) 
      return new XElement(xname); 

     if (input is string || input is int || input is float /* others */) 
      return new XElement(xname, input); 

     var type = input.GetType(); 
     var fields = type.GetFields(BindingFlags.Instance | 
            BindingFlags.NonPublic) 
         .Union(type.GetFields(BindingFlags.Instance | 
               BindingFlags.Public)); 

     var elems = fields.Select(f => f.GetValue(input) 
             .AsXml(f.Name)); 

     return new XElement(xname, elems); 
    } 
    public static void ToObject(this XElement input, object result) 
    { 
     if (input == null || result == null) 
      throw new ArgumentNullException(); 

     var type = result.GetType(); 
     var fields = type.GetFields(BindingFlags.Instance | 
            BindingFlags.NonPublic) 
         .Union(type.GetFields(BindingFlags.Instance | 
               BindingFlags.Public)); 

     var values = from elm in input.Elements() 
        let name = XmlConvert.DecodeName(elm.Name.LocalName) 
        join field in fields on name equals field.Name 
        let backType = field.FieldType 
        let val = elm.Value 
        let parsed = backType.AsValue(val, elm) 
        select new 
        { 
         field, 
         parsed 
        }; 

     foreach (var item in values) 
      item.field.SetValue(result, item.parsed);    
    } 

    public static object AsValue(this Type backType, 
             string val, 
             XElement elm) 
    { 
     if (backType == typeof(string)) 
      return (object)val; 
     if (backType == typeof(int)) 
      return (object)int.Parse(val); 
     if (backType == typeof(float)) 
      return (float)int.Parse(val); 

     object ret = FormatterServices.GetUninitializedObject(backType); 
     elm.ToObject(ret); 
     return ret; 
    } 
} 
public class Program 
{ 
    public static void Main(string[] args) 
    { 
     var obj = new { Matt = "hi", Other = new { ID = 1 } }; 
     var other = new { Matt = "zzz", Other = new { ID = 5 } }; 
     var ret = obj.AsXml(); 
     ret.ToObject(other); 
     Console.WriteLine(obj); //{ Matt = hi, Other = { ID = 1 } } 
     Console.WriteLine(other); //{ Matt = hi, Other = { ID = 1 } } 
    } 
} 
+0

+1 Wrapping è una splendida idea in uno scenario come questo. – Filburt

+0

Sì, ho appena provato a creare una soluzione rapida per mantenere e ripristinare oggetti basati su valori privati. Persistere è abbastanza facile; il problema arriva con il ripristino di loro. Se non si ha accesso a un parametro meno costruttore, potrebbe essere impossibile. –

+0

Non ho alcuna responsabilità se il codice di cui sopra fa esplodere il mondo e tutta la vita nell'universo finisce bruscamente. –

0
///Here OBJECT is Class name and Object_to_write is instance 
XmlSerializer serializer = new XmlSerializer(typeof(OBJECT)); 
using (TextWriter writer = new StreamWriter(@"C:\Xml.xml")) 
{ 
    serializer.Serialize(writer, OBJECT_to_Write); 
} 
+0

> L'oggetto proviene da una libreria di terze parti che non posso modificare. XmlSerializer può lanciare InvalidOprationException: [l'oggetto] non può essere serializzato perché non ha un costruttore senza parametri. –

Problemi correlati