保留未标记为可序列化的对象

时间:2010-04-07 20:28:28

标签: c# .net serialization serializable

我需要保留一个没有用serializable属性标记的对象。该对象来自第三方图书馆,我无法改变。

我需要将它存储在一个持久存储的位置,例如文件系统,因此最佳解决方案是将对象序列化为文件,但由于它未标记为可序列化,因此不是直截了当解。

这是一个非常复杂的对象,它还包含其他对象的集合。

你们对如何解决这个问题有任何意见吗?代码永远不会在生产环境中运行,因此我几乎可以使用任何解决方案和性能。

5 个答案:

答案 0 :(得分:9)

如果类型是公共等,

XmlSerializer可能是首先尝试的有用的东西

如果失败了,protobuf-net的v2(正在进行中,你需要从源代码构建,但我可以提供帮助)适用于未归属的对象,非常适合你控制之外的类型 - 你只需要告诉它什么包括(通过DSL)。 v2代码不完整,但它涵盖了大多数常见场景,包括集合等(不完整的工作主要是回调和枚举)。

答案 1 :(得分:5)

您可以编写一个递归方法,使用反射来运行对象图以保持对象...将其放回可能会困难得多。谁知道这些对象中是否有任何对象持有对非托管或系统资源的引用。如果我要做这个坚果的任何事情,我会选择该类型的.GetFields(...)方法。

另一个想法......

如果您只是这样做以加快开发,为什么不用自己的适配器类包装它们的clases。这将允许您使用自己的简化模拟类替换第三方库,以便以后更好地替换和重用。

生病了...... 这比我认为的那样容易。 (虽然这有效......请考虑包装第三方类。)

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

答案 2 :(得分:3)

答案 3 :(得分:2)

我不知道你的使用是否有点过分,但我最近一直在玩db4o。它将持久保存任何对象,只需调用IObjectContainer.Store(object),它是轻量级的,基于文件的。不需要任何安装。

我还没有遇到任何问题。

答案 4 :(得分: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); 
}