Pergunta

Preciso persistir um objeto que não esteja marcado com o atributo serializável. O objeto é de uma biblioteca de terceiros que não posso mudar.

Eu preciso armazená -lo em um local persistente, como, por exemplo, o sistema de arquivos, para que a solução ideal seria serializar o objeto a um arquivo, mas como não é marcado como serializável, isso não é uma solução direta.

É um objeto bastante complexo, que também contém uma coleção de outros objetos.

Vocês têm alguma opinião sobre como resolver isso? O código nunca será executado em um ambiente de produção, por isso estou bem com quase qualquer solução e desempenho.

Foi útil?

Solução

XmlSerializer pode ser uma primeira coisa útil a tentar, se os tipos forem públicos etc.

Se isso falhar, v2 do protobuf -net (em andamento, você precisará construir a partir da fonte, mas eu posso ajudar) trabalha com objetos não atribuídos, tão ideais para tipos fora do seu controle - você só precisa dizer o que incluir ( via DSL). O código V2 não está completo, mas abrange cenários mais comuns, incluindo coleções etc. (o trabalho incompleto é principalmente retornos de chamada e enums).

Outras dicas

Você pode escrever um método recursivo que atingisse o gráfico de objeto usando a reflexão para persistir o objeto ... colocá -lo de volta pode ser muito mais difícil. Quem sabe se algum desses objetos está mantendo referências a recursos não gerenciados ou do sistema. Se eu fosse fazer qualquer coisa tão maluca, iria para o .GetFields(...) Método no tipo.

Outra ideia...

Se você está fazendo isso apenas para acelerar o desenvolvimento, não envolve suas clases com suas próprias classes de adaptador. Isso permitiria que você substituísse as bibliotecas de terceiros por suas próprias classes simplárias simplificadas e permitissem melhores chances de substituição e reutilização mais tarde.

Doente como está ... Isso foi mais fácil do que eu pensei que seria. (Enquanto isso funciona ... Por favor, considere encerrar as classes de terceiros.)

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

Não sei se é um exagero para o seu uso, mas tenho brincado com db4o recentemente. Ele persistirá qualquer objeto, basta ligar para o iObjectContainer.store (objeto) e é leve e baseado em arquivos. Não requer nenhuma instalação.

Ainda não tive problemas com isso.

///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); 
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top