4

我很想知道如何使用带有 FormatterAssemblyStyle.Full 的二进制格式化程序的汇编格式来“打破”反序列化。

文档说明了这一点:

在完整模式下,反序列化期间使用的程序集必须与序列化期间使用的程序集完全匹配。

我想如果我用程序集的 1.0.0.0 版本序列化一个对象(_person,它是一个具有值类型字段的简单类),然后尝试用程序集的 v1.2.0.0(更新 AssemblyInfo.cs)反序列化,我会得到一个反序列化异常。但是,它成功反序列化。

我错过了什么吗?

我正在使用以下内容序列化到文件:

                BinaryFormatter formatter = new BinaryFormatter();
                formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full;

                using (Stream stream = new FileStream(fileName,
                                                     FileMode.Create,
                                                     FileAccess.Write,
                                                     FileShare.None))
                {
                    formatter.Serialize(stream, _person);
                    stream.Close();
                }

然后使用以下反序列化:

                BinaryFormatter formatter = new BinaryFormatter();
                formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full;

                using (Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    _person = (Person)formatter.Deserialize(stream);
                   stream.Close();
                }

我还注意到使用 FormatterAssemblyStyle.Full 和 FormatterAssemblyStyle.Simple 生成的序列化文件都包含完整的版本信息(例如版本 1.0.0.0 Culture = 中性,PublicKeyToken = null) - 我认为 Simple 不会添加所有这些信息?(请参阅此处的格式化程序和程序集名称部分

更新1:

到目前为止,我看到的唯一区别是,如果我使用 Simple,那么我不必OptionalField属性放置到序列化类中的新字段中,就可以成功地反序列化旧版本。如果我使用 Full,那么它会抛出异常,除非我将OptionalField属性放在新字段上。如果使用非强命名的程序集,这是唯一的区别吗?

有关详细信息,请参阅

提前致谢

4

1 回答 1

9

文档FormatterAssemblyStyle.Full实际上说了两件事:

  1. Assembly.Load方法将用于加载程序集。
  2. 反序列化期间使用的程序集必须与序列化期间使用的程序集完全匹配。

通过 Assembly.Load 加载程序集

加载程序集时,还会检查程序集版本,但前提是程序集是强命名的。Assembly Versioning的文档是这样说的:

为了版本控制,运行时区分常规程序集和强名称程序集。版本检查仅发生在强名称程序集上。

要对程序集进行强命名,只需按照如何:使用强名称对程序集进行签名中的步骤。此外,即使您为没有强名称的程序集指定完全限定的程序集名称,AssemblyName 文档也会说明以下内容:

提供显示名称时,约定 StrongName =null 或 PublicKey= null 表示需要对简单命名的程序集进行绑定和匹配。

因此,即使使用Assembly.Load方法,运行时也将始终加载常规程序集而不进行版本检查。

完全反序列化

整个程序集必须与反序列化期间使用的程序集相匹配,这并不完全正确。只有正在反序列化的类(以及对象图中的所有其他类)应该匹配。在每个反序列化的类中,只有字段应该匹配,您可以随意添加新方法。Version Tolerant Serialization更详细地介绍了这一点。

总而言之,是的,如果您没有强命名的程序集,那么唯一的区别在于反序列化的容忍度。因此,您可以使用Full反序列化OptionalFieldAttribute还是Simple反序列化,具体取决于您的上下文。

于 2012-10-01T13:01:46.720 回答