【问题标题】:Serialize an object without the object's information在没有对象信息的情况下序列化对象
【发布时间】:2013-02-04 19:51:57
【问题描述】:

我的情况是,我只需要将对象成员的值序列化到文件中。

例如,如果对象包含 3 个字符串成员,我希望序列化的输出只有这 3 个字符串,而没有 Binaryformatter 添加的序列化元数据,例如版本、文化和程序集对象的名称。

一种选择是直接编写对象的每个成员,但我想避免这种情况,因为我有很多需要像这样序列化的类,我不想编写一个以不同方式处理它的函数每个班级。

要求:

我希望能够写入任何类型的文件,我希望将成员的值转换为字节(进入缓冲区或直接进入文件)并能够将这些字节写入特定位置在文件中。

是否有方法或 API 仅序列化对象成员的值?

【问题讨论】:

  • 你打算在某个时候反序列化它吗?
  • 可能不会,但如果我需要反序列化对象的成员,我可能会单独读取每个成员。
  • 有任意数量的替代序列化 API; xml、json、protobuf 等。所有这些都可以在没有类型元数据信息的情况下使用。但是这里缺少很多要求/上下文...
  • @Matan - 使用反射,您可以询问对象,然后将您想要的数据从对象写入文件。这将是通用的(您只需编写一次),并且您可以以您想要的格式编写文件(与使用现有的序列化 API 相比)。链接到微软的反射文档 -> msdn.microsoft.com/en-us/library/ms173183(v=vs.80).aspx
  • @DavidHope +1 使用反射来“询问”对象。

标签: c# serialization binaryformatter


【解决方案1】:

马坦,

这是我出于完全不同的目的而编写的一些代码,但它需要一个未知对象并将其序列化为 XML 文件(已更新以包含更好的编码实践)。

    void objectToXMLFile(String fn, object o)
    {
        XmlTextWriter textWriter = new XmlTextWriter(fn, null);

        System.Type type = o.GetType();
        PropertyInfo[] piList = type.GetProperties();

        textWriter.WriteStartDocument();

        textWriter.WriteStartElement("attributeList");

        foreach (PropertyInfo pi in piList)
        {
            textWriter.WriteStartElement("attribute");

            textWriter.WriteStartElement("name");
            textWriter.WriteString(pi.Name);
            textWriter.WriteEndElement();

            textWriter.WriteStartElement("value");
            textWriter.WriteString(pi.GetValue(o).ToString());
            textWriter.WriteEndElement();

            textWriter.WriteStartElement("dataType");
            textWriter.WriteString(pi.PropertyType.Name);
            textWriter.WriteEndElement();

            textWriter.WriteEndElement();
        }
        textWriter.WriteEndElement();
        textWriter.WriteEndDocument();
        textWriter.Close();
    }

【讨论】:

  • 在这种情况下,将XmlSerializer 与简单的AttributeList 数据模型结合使用不是更安全,因为它可以更好地处理特殊情况(例如包含需要XML 转义的字符的值? )
  • 对于我的代码,是的,这可能是更好的做法。但是,代码是作为在 C# 中使用反射的示例提供的,因此仍然密切相关。
  • 好吧,我收回我的话,这个反思可以很好地为我所用。 =] 我根本不知道反射的存在。
  • 不幸的是,这个解决方案对我不利,我的对象有多种类型的成员,如 int 和 string,最后我需要将成员转换为字节,反射不需要给我最好的解决方案,因为现在我需要对每个成员进行字节转换,直接写每个对象几乎一样好。
  • 抛开要求不谈,这段代码的性能成本非常高。 @David Hope,如果您坚持自己格式化 XML,并且必须在内存中(而不是文件)进行,至少使用 StringWriterStringBuilder。您编写的代码会分配大量字符串 - 因为 String 是不可变的,所以每次使用 += 时,您都会在内存中复制到目前为止的 XML。
【解决方案2】:

如果您最终只使用反射来编写所需的属性,您可能需要考虑一些性能影响。

使用反射很慢。反射类型本身代价高昂,然后通过调用PropertyInfo.GetValue动态调用PropertyInfo很慢。

另一种方法是构建一个调用属性并写入其值的表达式树,然后将此表达式编译为Action。您可以将这些Action 实例缓存在由您正在序列化的对象的Type 键入的字典中,并在您想要序列化对象时调用正确的实例。

这样会快得多,也不会在 GC 上产生太多负载。

您可以考虑的另一种选择是在构建时生成代码 - 您可以生成一个类来快速且廉价地序列化您的目标类型。在某些情况下,这是一个不错的选择。

【讨论】:

  • 这似乎不是最好的选择,我的问题不是如何存储所有属性是如何序列化它们..
  • 我有多种类,将“调用”属性并写入其值的函数将针对每个类以不同的方式实现,这是我想要避免的。我正在寻找一个 API,它只会写入任何类型对象的属性值。
  • @Matan,为什么会有不同的实现方式?您可以编写 1 个函数来获取要序列化的目标类型,使用反射检查类型的属性,并生成可以写入此类型实例的属性的快速通用 Action。
猜你喜欢
  • 2012-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-06
  • 1970-01-01
  • 2018-08-26
  • 2018-09-04
  • 1970-01-01
相关资源
最近更新 更多