【问题标题】:Deserializing properties into a pre-existing object将属性反序列化为预先存在的对象
【发布时间】:2010-02-26 12:38:43
【问题描述】:

是否可以使用任何标准序列化程序反序列化对象属性,而无需创建新对象?

问题是,有问题的对象非常复杂(它们只能由特殊的工厂创建,并且它们的类型是在运行时动态生成的),但是它们有一些已知的属性,我想将它们存储在外部文件中(最好是 xml,但二进制也可以),稍后(可能在应用程序重新启动后),我希望将存储的属性设置回我提供的对象。

似乎所有标准序列化程序都只能为我生成一个新对象(这也需要一个公共无参数构造函数),我必须从中手动分配所有属性。这与我想避免的手动序列化没有太大区别,因为一组序列化的属性非常大,并且可能会在项目生命周期内更改几次。在这一点上,我已经非常接近编写自己的轻量级序列化程序了,但也许有人可以建议一种更标准的方式来做这些事情?

【问题讨论】:

    标签: c# serialization


    【解决方案1】:

    protobuf-net 有一个Serializer.Merge 方法,可让您反序列化为现有实例。仅写入在流中找到的值(它不会擦除对象)。

    不是微软,但相当稳定。

    对此进行扩展;获得处理所有常见场景的强大序列化是(我从痛苦的经验中知道)很多工作。我的建议肯定是尽可能重用现有代码。 protobuf-net 似乎提供了你需要的一切;当前的二进制文件只需要你装饰你的类(非常类似于来自 WCF 的 [DataContract] - 事实上它甚至支持 [DataContract] / [DataMember]),但工作已经到位,即使是针对 POCO 也可以工作 - 所以你可以将它与您无法控制的类型一起使用。

    【讨论】:

    • 这不是在字段级别而不是在请求的属性级别上工作吗?
    • @Lucero - 它适用于字段和属性;这取决于你告诉它做什么。
    • 感谢您提供有趣的链接,但我不希望为这样一个相当简单的任务使用全新的第三方组件。还有一个缺点是它不是 xml。
    【解决方案2】:

    您可以使用FormatterServices 类。

    你有一本课本:

    [Serializable]
    class Book
    {
        public string Title { get; set; }
    
        public string Author { get; set; }
    
        // Constructor for setting new values. 
        public Book(string title, string author)
        {
            Title = title;
            Author = author;
        }
    }
    

    你可以这样序列化它:

    var book = new Book("Moby Dick", "Herman Melville");
    
    string path = Path.GetTempFileName();
    
    var bf = new BinaryFormatter();
    using (var fs = new FileStream(path, FileMode.Create))
        bf.Serialize(fs, book);
    

    如果您的对象被修改:

    // Edit object
    book.Title = "Foo";
    Console.WriteLine("{0}, {1}", book.Title, book.Author);
    

    您可以使用以下代码恢复它:

    Book temp;
    using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
        temp = (Book) bf.Deserialize(fs);
    
    MemberInfo[] members = FormatterServices.GetSerializableMembers(typeof (Book));
    FormatterServices.PopulateObjectMembers(book, members, FormatterServices.GetObjectData(temp, members));
    
    // Object state is back
    Console.WriteLine("{0}, {1}", book.Title, book.Author);
    

    【讨论】:

      【解决方案3】:

      您可以实现自己的灵活“序列化程序”来处理这个问题。反射为您提供所需的一切。

      【讨论】:

        【解决方案4】:

        您可以使用FormatterServices.PopulateObjectMembers 方法,它似乎是专门为这项任务设计的...

        【讨论】:

        • 到那时,您将不得不解析流以将值放入object s,获得MemberInfo s, 处理了所有复杂的子数据等。老实说,简单地使用一种方法来设置 值几乎没有提供什么——那时你可以只使用反射。
        猜你喜欢
        • 2014-08-22
        • 1970-01-01
        • 1970-01-01
        • 2011-12-21
        • 1970-01-01
        • 1970-01-01
        • 2017-03-21
        • 1970-01-01
        相关资源
        最近更新 更多