【问题标题】:C# Binary serialization and AssemblyFormat with FormatterAssemblyStyle.Full带有 FormatterAssemblyStyle.Full 的 C# 二进制序列化和 AssemblyFormat
【发布时间】:2012-09-05 07:02:51
【问题描述】:

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

documentation 对此表示:

在完整模式下,反序列化过程中使用的程序集必须匹配 正是序列化期间使用的程序集。

我想如果我用 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 不会添加所有这条信息? (请参阅this 中的格式化程序和程序集名称部分)

更新 1:

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

详情请见this

提前致谢

【问题讨论】:

    标签: c# .net winforms visual-studio-2010 serialization


    【解决方案1】:

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

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

    通过 Assembly.Load 加载程序集

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

    为了版本控制,运行时区分常规程序集和强名称程序集。版本检查仅适用于强名称程序集。

    要对程序集进行强命名,只需按照How to: Sign an Assembly with a Strong Name 中的步骤操作即可。 此外,即使您为没有强名称的程序集指定完全限定的程序集名称,AssemblyName docs 也会声明以下内容:

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

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

    完全反序列化

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

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

    【讨论】:

    • 感谢您的信息;但是为什么文档说明Full:“反序列化期间使用的程序集必须与序列化期间使用的程序集完全匹配。Assembly类的Load方法用于加载程序集。” - 我认为 Load 方法将始终检查版本详细信息,因此发现保存的文件版本与反序列化文件的程序集版本不匹配?
    • 我已经更新了我的答案,希望这能澄清一点。
    猜你喜欢
    • 2011-06-08
    • 2016-07-27
    • 2017-10-18
    • 1970-01-01
    • 1970-01-01
    • 2012-06-15
    • 2010-12-17
    • 2015-09-17
    • 2016-02-21
    相关资源
    最近更新 更多