简体   繁体   English

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

[英]Persist an object that is not marked as serializable

I need to persist an object that is not marked with the serializable attribute. 我需要保留一个没有用serializable属性标记的对象。 The object is from a 3rd party library which I cannot change. 该对象来自第三方库,我无法更改。

I need to store it in a persist place, like for example the file system, so the optimal solution would be to serialize the object to a file, but since it isn't marked as serializable, that is not a straight forward solution. 我需要将它存储在一个持久的位置,例如文件系统,因此最佳解决方案是将对象序列化为文件,但由于它未标记为可序列化,因此这不是一个直接的解决方案。

It's a pretty complex object, which also holds a collection of other objects. 它是一个非常复杂的对象,它还包含其他对象的集合。

Do you guys have any input on how to solve this? 你们有任何关于如何解决这个问题的意见吗? The code will never run in a production environment, so I'm ok with almost any solution and performance. 代码永远不会在生产环境中运行,因此我几乎可以使用任何解决方案和性能。

XmlSerializer may be a useful first thing to try, if the types are public etc 如果类型是公共等, XmlSerializer可能是一个有用的第一件事

If that fails, v2 of protobuf-net (in progress, you'd need to build from source, but I can help) works with unattributed objects, so ideal for types outside your control - you just need to tell it what to include (via a DSL). 如果失败了,protobuf-net的v2(正在进行中,您需要从源代码构建,但我可以提供帮助)适用于未归属的对象,因此非常适合您控制之外的类型 - 您只需要告诉它要包含哪些内容(通过DSL)。 The v2 code isn't complete, but it covers most common scenarios, including collections etc (the incomplete work is mainly callbacks and enums). v2代码不完整,但它涵盖了大多数常见场景,包括集合等(不完整的工作主要是回调和枚举)。

You could write a recursive method that would run down the object graph using reflection to persist the object... Putting it back could be much more difficult. 您可以编写一个递归方法,使用反射来运行对象图以保持对象...将其放回可能会困难得多。 Who knows if any of those objects are holding references to unmanaged or system resources. 谁知道这些对象中是否有任何对象持有对非托管或系统资源的引用。 If i was to do anything this nuts, I would go for the .GetFields(...) method on the type. 如果我要做这个坚果的任何事情,我会选择类型上的.GetFields(...)方法。

Another idea... 另一个想法......

If you are only doing this to speed up development why not wrap their clases with your own adapter classes. 如果您只是为了加速开发,那么为什么不用自己的适配器类包装它们的clases。 This would allow you to replace the third party libraries with your own simplifed mock classes and allow for better chance for replacement and reuse later. 这将允许您使用自己的简化模拟类替换第三方库,以便以后更好地替换和重用。

Sick as it is... This was easier then I thought it would be. 生病了...这比我想的那样容易。 (While this works... please consider wrapping the third party classes.) (虽然这有效......请考虑包装第三方课程。)

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

I don't know if it is overkill for your usage, but I have been playing around with db4o lately. 我不知道你的用法是否有点过分,但我最近一直在玩db4o It will persist any object, just call IObjectContainer.Store(object), and it is lightweight and file-based. 它将持久保存任何对象,只需调用IObjectContainer.Store(object),它是轻量级的,基于文件的。 Does not require any installation. 不需要任何安装。

I haven't had any problems with it yet. 我还没有遇到任何问题。

///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); 
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从标记为可序列化的对象获取XMlNode内容 - Get the XMlNode content from object marked as serializable IsSerializable为标记为Serializable的对象返回“false” - IsSerializable returning “false” for an object marked Serializable 为什么二进制序列化要求将对象标记为可序列化? - Why does Binary Serialization require the object to be marked as serializable? 如何执行未标记为可序列化的对象的深层副本(在C#中)? - How to perform a deep copy of an object not marked as serializable (in C#)? 为什么BinaryFormatter会尝试将标记为[Serializable]的类型的对象强制转换为IConvertible? - Why would BinaryFormatter attempt to cast an object of type marked [Serializable] to IConvertible? 当一个对象派生自MarshalByRefObject并且还标记为[Serializable]时会发生什么? - what happens when an object derives from MarshalByRefObject and is also marked [Serializable]? C#无法序列化对象,因为MainViewModel没有标记为Serializable - C# Cannot serialize object because MainViewModel is not marked Serializable Tableadapters是否标记为可序列化? - Tableadapters Not Marked as serializable? 未标记为可序列化错误 - Not marked as Serializable error ExtensionDataObject未标记为可序列化 - ExtensionDataObject not marked as serializable
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM