【问题标题】:Using DataContractSerializer to serialize, but can't deserialize back使用 DataContractSerializer 进行序列化,但无法反序列化
【发布时间】:2011-06-27 23:13:02
【问题描述】:

我有以下两个功能:

public static string Serialize(object obj)
{
    DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
    MemoryStream memoryStream = new MemoryStream();
    serializer.WriteObject(memoryStream, obj);
    return Encoding.UTF8.GetString(memoryStream.GetBuffer());
}

public static object Deserialize(string xml, Type toType)
{
    MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(xml));
   // memoryStream.Position = 0L;
    XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(memoryStream, Encoding.UTF8, new XmlDictionaryReaderQuotas(), null);
    DataContractSerializer dataContractSerializer = new DataContractSerializer(toType);
    return dataContractSerializer.ReadObject(reader);
}

第一个似乎可以将对象序列化为 xml 字符串。 XML 看起来有效,没有损坏的标签,开头或结尾没有空格等。现在第二个函数不想将我的 xml 字符串反序列化回对象。在我得到的最后一行:

反序列化时出错 [MY OBJECT TYPE HERE] 类型的对象。 根级别的数据无效。 第 1 行,位置 1。

我做错了什么?我尝试重写 Deserialize 函数几次,它似乎总是同一种错误。谢谢!

哦,这就是我调用这两个函数的方式:

SomeObject so = new SomeObject();
string temp = SerializationManager.Serialize(so);
so = (SomeObject)SerializationManager.Deserialize(temp, typeof(SomeObject));

【问题讨论】:

    标签: c# c#-4.0 xml-serialization datacontractserializer


    【解决方案1】:

    其他解决方案是:

    public static T Deserialize<T>(string rawXml)
    {
        using (XmlReader reader = XmlReader.Create(new StringReader(rawXml)))
        {
            DataContractSerializer formatter0 = 
                new DataContractSerializer(typeof(T));
            return (T)formatter0.ReadObject(reader);
        }
    }
    

    备注:有时会发生原始 xml 包含例如:

    &lt;?xml version="1.0" encoding="utf-16"?&gt;

    那么你当然不能使用其他示例中使用的 UTF8 编码..

    【讨论】:

      【解决方案2】:

      这最适合 XML 反序列化

       public static object Deserialize(string xml, Type toType)
          {
      
              using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
              {
                  System.IO.StreamReader str = new System.IO.StreamReader(memoryStream);
                  System.Xml.Serialization.XmlSerializer xSerializer = new System.Xml.Serialization.XmlSerializer(toType);
                  return xSerializer.Deserialize(str);
              }
      
          }
      

      【讨论】:

      • 您可以为您的建议提供一些解释。请看How to Answer
      【解决方案3】:

      我最终做了以下工作。

      public static string Serialize(object obj)
      {
          using (MemoryStream memoryStream = new MemoryStream())
          {
              DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
              serializer.WriteObject(memoryStream, obj);
              return Encoding.UTF8.GetString(memoryStream.ToArray());
          }
      }
      
      public static object Deserialize(string xml, Type toType)
      {
          using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
          {
              XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(memoryStream, Encoding.UTF8, new XmlDictionaryReaderQuotas(), null);
              DataContractSerializer serializer = new DataContractSerializer(toType);
              return serializer.ReadObject(reader);
          }
      }
      

      看来主要问题出在调用stream.GetBuffer() 时的Serialize 函数。调用 stream.ToArray() 似乎有效。

      【讨论】:

      • GetBuffer() 失败,因为 MemoryStream 的缓冲区是按 256 字节块分配的,所有块的所有字节,甚至是字符串的终止 '\0' 之后未使用的零字节都由 GetBuffer( )。这意味着生成的字符串正确地有一堆尾零。
      【解决方案4】:

      这是我一直以来的做法:

          public static string Serialize(object obj) {
              using(MemoryStream memoryStream = new MemoryStream())
              using(StreamReader reader = new StreamReader(memoryStream)) {
                  DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
                  serializer.WriteObject(memoryStream, obj);
                  memoryStream.Position = 0;
                  return reader.ReadToEnd();
              }
          }
      
          public static object Deserialize(string xml, Type toType) {
              using(Stream stream = new MemoryStream()) {
                  byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
                  stream.Write(data, 0, data.Length);
                  stream.Position = 0;
                  DataContractSerializer deserializer = new DataContractSerializer(toType);
                  return deserializer.ReadObject(stream);
              }
          }
      

      【讨论】:

      • 对于反序列化,将 GetBytes/Write 替换为 "using (StreamWriter writer = new StreamWriter(stream, encoding) { writer.Write(xml); ... }" 可能更有效避免额外的 byte[] 缓冲区。
      • 这太棒了,而且仍然非常有用。最重要的是,这是正确的。
      • 我也使用过这些方法,但是在序列化-反序列化基类的派生类时遇到了一点问题。我不得不稍微修改一下序列化方法 (link) 以提供基类类型。
      猜你喜欢
      • 1970-01-01
      • 2021-02-13
      • 1970-01-01
      • 2018-05-09
      • 2013-03-03
      • 1970-01-01
      • 1970-01-01
      • 2011-09-29
      • 1970-01-01
      相关资源
      最近更新 更多