2010-04-07 21 views
21

Necesito persistir un objeto que no está marcado con el atributo serializable. El objeto es de una biblioteca de terceros que no puedo cambiar.Persistir en un objeto que no está marcado como serializable

Necesito guardarlo en un lugar persistente, como por ejemplo el sistema de archivos, entonces la solución óptima sería serializar el objeto a un archivo, pero como no está marcado como serializable, no es una línea recta solución avanzada

Es un objeto muy complejo, que también tiene una colección de otros objetos.

¿Ustedes tienen alguna opinión sobre la manera de resolver esto? El código nunca se ejecutará en un entorno de producción, así que estoy de acuerdo con casi cualquier solución y rendimiento.

+12

famosas últimas palabras ... 'El código no se ejecutará en un environment' producción: OP –

+0

@Matthew: Sí, Derecha :-) +1 – driis

+0

Heh, lo sé :) Es solo para acelerar un poco el tiempo de calentamiento durante el desarrollo, por lo que no tiene mucho sentido en ningún otro lado. – lasseeskildsen

Respuesta

9

XmlSerializer puede haber una primera cosa útil para tratar, si los tipos son públicos, etc

Si eso no funciona, v2 de protobuf-net (en curso, que te nee d para compilar desde la fuente, pero puedo ayudar) funciona con objetos no atribuidos, por lo que es ideal para tipos que están fuera de su control; solo necesita decirle qué incluir (a través de una DSL). El código v2 no está completo, pero cubre los escenarios más comunes, incluidas las colecciones, etc. (el trabajo incompleto es principalmente devoluciones de llamada y enumeraciones).

+0

protobuf-net se ve muy bien. ¿Requiere constructores sin parámetros? – lasseeskildsen

+0

@lasseeskildsen - por el momento lo hace, sí - pero como soy el propietario estoy seguro de que podría agregar el enfoque de WCF (de no llamar a ningún ctor). Solo tomaría unos minutos (es solo una llamada a 'FormatterServices.GetUninitializedObject'). –

+0

Si tiene un ejemplo de la API de terceros, podría probablemente crear un ejemplo de v2. –

2

No sé si es un exceso para su uso, pero yo he estado jugando con db4o últimamente. Persistirá en cualquier objeto, simplemente llame a IObjectContainer.Store (object), y es liviano y basado en archivos. No requiere ninguna instalación.

no he tenido ningún problema con ella todavía.

3

Esta es una manera que podría hacerlo:

http://www.codeproject.com/KB/dotnet/Surrogate_Serialization.aspx

aquí está el enlace de MSDN mostrarlo:

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

+0

Los enlaces ya no funcionan. Primer artículo: [enlace] (https: //web.archive.org/web/20101213020136/http: //www.codeproject.com/kb/dotnet/Surrogate_Serialization.aspx) Segundo artículo: [enlace] (https://web.archive.org/web/20141231105711/http://msdn) .microsoft.com/es-us/magazine/cc188950.aspx) – milosa

5

Se puede escribir un método recursivo que correr por el gráfico de objetos usando la reflexión para conservar el objeto ... poner de nuevo podría ser mucho más difícil. Quién sabe si alguno de esos objetos contiene referencias a recursos no administrados o del sistema. Si tuviera que hacer algo así de loco, iría por el método .GetFields(...) en el tipo.

Otra idea ...

Si sólo está haciendo esto para acelerar el desarrollo de por qué no envolver sus clases con sus propias clases de adaptador. Esto le permitiría reemplazar las bibliotecas de terceros con sus propias clases simuladas simplificadas y permitir una mejor posibilidad de reemplazo y reutilización más adelante.

Enfermo como es ... Esto fue más fácil de lo que pensé que sería. (Aunque esto funciona ... Por favor considere envolver las clases de terceros.)

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 El envolver es una idea espléndida en un escenario como este. – Filburt

+0

Sí, intenté crear una solución rápida para conservar y restaurar objetos basados ​​en valores privados. Persistir es bastante fácil; el problema viene con restaurarlos. Si no tiene acceso a un constructor de parámetros menores, puede ser imposible. –

+0

No tengo ninguna responsabilidad si el código anterior hace que el mundo explote y toda la vida en el universo llega a un final abrupto –

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

> El objeto es de una biblioteca de terceros que no puedo cambiar. XmlSerializer podría arrojar InvalidOprationException: [el objeto] no se puede serializar porque no tiene un constructor sin parámetros. –

Cuestiones relacionadas