.NET序列化在不同框架版本中的稳定性

9
我正在处理一个项目,需要在关闭前序列化数据结构,并在启动时从这个序列化的数据中恢复其状态。
去年我们在构建.NET 1.1时遇到了一个棘手的问题,即:
我们的代码在.NET 2.0上运行
客户升级了一些软件,以某种方式将1.1设置为默认版本
我们的代码在.NET 1.1上运行,并且无法反序列化其存储的状态
通过禁止特定软件升级来“解决”了这个问题,现在我们的目标是.NET 2.0框架(因此不可能在1.1上运行),所以这个问题应该不会再出现。
这个序列化问题在2.0及更高版本的框架中是否仍然存在不兼容性?如果我们使用将我们的代码修复为2.0.50727,那么在2.0.50727.1434和2.0.50727.nnnn(一些未来的版本)之间发生变化的几率有多大?被序列化的数据结构是来自标准类库的数组、映射、字符串等等。
此外,2.0.50727框架是否保证始终安装,即使进行了进一步的.NET升级?欢迎提供Microsoft文档的指针。
7个回答

7
机会很小(但不为零!)在框架版本之间进行更改。意图是您应该能够使用二进制序列化和远程通信,在运行不同框架版本的客户端和服务器之间进行通信。 .NET 1.x和2.0之间的不兼容性是错误,可使用补丁解决。
然而,二进制序列化存在其他问题,尤其是对您正在序列化的结构的版本支持差。根据您描述的用例,Xml序列化是明显的选择:如果您不介意依赖于.NET 3.x,则DataContractSerializer比XmlSerializer更灵活。
无法保证将来的Windows版本上始终安装.NET framework 2.0。但我相信微软将努力确保大多数.NET 2.0应用程序在.NET 4.x及更高版本上运行不变。我没有任何参考资料:任何这样的承诺都只适用于下一个Windows版本(Windows 7)。

1
我大部分都同意,但我不明白Windows 7的观点...我对.NET 4.x和Windows 7都不是很了解,但我预计.NET 4.x应该是Vista和/可能/ XP兼容的。当然,我可能有些无知 ;-p - Marc Gravell
我的意思是,尽管微软可能承诺在Windows 7中同时发布.NET 2.0-3.5和.NET 4.0,但他们不太可能今天就对随后的Windows版本将发布哪些框架版本做出承诺。 - Joe

4

经验法则通常是:XML序列化应该能够适应新的框架版本,因此可以长期存储,但二进制序列化不能(因此只应该是短暂的)。


1
要注意的是,BinaryFormatter等可能会出现问题...有一些二进制格式是以数据为中心而不是类型为中心的,可以被视为此目的类似于“紧凑型xml”。其中之一是“protobuf-net” ;-p - Marc Gravell

3
你使用了哪种序列化程序?在许多方面,像XmlSerializer或DataContractSerializer这样的序列化程序可以为你屏蔽许多细节,并提供更简单的可扩展性选项。无疑,某个时候需要新的CLR版本 - 因此我认为没有人能对2.0.50727做出任何保证;不过短期内应该是安全的。而且我希望会有更少的破坏性变化...
[根据另一个回复的说明进行了更新]
如果你想要一个二进制格式以节省空间/提高性能,那么另一种选择是使用不同的二进制序列化程序。例如,protobuf-net适用于所有.NET变体*,但由Google设计的二进制格式是跨平台兼容的(Java、C++等)- 使其非常便携、快速和小巧。
*=我没有在微型框架上尝试过,但CF、Silverlight、Mono、.NET 2.0等都支持。

2
如果兼容性是一个问题,那么ISerializable接口可能是您需要的解决方案。该接口使您对序列化项目的控制更加灵活。如需了解更多信息,请参阅MSDN上的文章

2
我有两件事要补充到其他答案中...
首先,利用自定义的SerializationBinder可以解决导入旧版序列化数据时遇到的许多困难。
其次,我认为为任何持久化数据编写广泛的单元测试是必须的。我总是做两个特别的测试:
1.往返测试-您能否将对象序列化和反序列化,并获得完全相同的结果?
2.旧版导入测试-确保您从应用程序的每个发布版本中导出了序列化数据的版本。导入数据并检查是否如预期地返回了所有内容。

0

您不必使用XML来获得更高的灵活性和版本控制。

我使用了Simon Hewitt的开源库,参见在.NET中优化序列化 - 第2部分,而不是默认的.NET序列化。它提供了一些自动化,但本质上您可以控制被序列化和反序列化的信息流。对于版本控制,(文件)版本可以首先进行序列化,而在反序列化时,信息流的解释方式取决于版本。

这很简单,尽管由于显式序列化/反序列化而有些繁琐。

作为奖励,它比大型数据集的默认序列化/反序列化快20-40倍,并且占用更少的空间(但在您的情况下可能不重要)。


0

理论上,XML 应该在不同版本的 .NET Framework/.NET Core/.NET 之间始终是可移植的。但总有例外。

例如,如果您正在以 XML 格式传输 System.Data.DataTable,并且其中一些数据表包含类型为 System.Guid 的列,则可能会遇到意外情况!请考虑以下示例代码:

using System;
using System.Data;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

public class Program
{
    internal static string SerializeToXml<T>(T input)
    {
        var writerSettings = new XmlWriterSettings()
        {
            Encoding = new UTF8Encoding(false),
            Indent = true
        };
        using (var stream = new MemoryStream())
        using (var writer = XmlWriter.Create(stream, writerSettings))
        {
            (new XmlSerializer(typeof(T))).Serialize(writer, input);
            return Encoding.UTF8.GetString(stream.ToArray());
        }
    }

    public static void Main()
    {
        var dt = new DataTable("Name");
        dt.Columns.Add("Example", typeof(Guid));
        Console.WriteLine(SerializeToXml(dt));
    }
}

与大多数其他系统类型不同,System.Guid 在列定义中包含一个特定版本的 msdata:DataType 属性,当不兼容的运行时尝试反序列化它时,会抛出一个 System.InvalidOperationException: There is an error in XML document (.., ...) 包装了一个 System.ArgumentException: Column requires a valid DataType

.NET Framework 4.7.2 输出:

<?xml version="1.0" encoding="utf-8"?>
<DataTable>
  <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="Name" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Name">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="Example" msdata:DataType="System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" type="xs:string" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:schema>
  <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" />
</DataTable>

.NET Core 3.1 输出:(是的,它输出版本号为 4.0.0.0)

<?xml version="1.0" encoding="utf-8"?>
<DataTable>
  <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="Name" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Name">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="Example" msdata:DataType="System.Guid, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" type="xs:string" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:schema>
  <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" />
</DataTable>

.NET 5 输出:

.NET 5
<?xml version="1.0" encoding="utf-8"?>
<DataTable>
  <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="Name" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Name">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="Example" msdata:DataType="System.Guid, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" type="xs:string" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:schema>
  <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" />
</DataTable>

.NET 6输出:

<?xml version="1.0" encoding="utf-8"?>
<DataTable>
  <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="Name" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Name">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="Example" msdata:DataType="System.Guid, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" type="xs:string" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:schema>
  <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" />
</DataTable>

.NET 7 输出:

<?xml version="1.0" encoding="utf-8"?>
<DataTable>
  <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="Name" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Name">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="Example" msdata:DataType="System.Guid, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" type="xs:string" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:schema>
  <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" />
</DataTable>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接