【问题标题】:Binary serialization and automatic properties二进制序列化和自动属性
【发布时间】:2013-02-28 10:38:23
【问题描述】:

我有这样的课:

public class Foo
{
    public IBar {get;set;}
    //tons of other properties
}

public interface IBar
{
    //whatever
}

该类用于二进制序列化(BinaryFormatter 的标准使用)。 IBar 的实现标有 [Serializable],因此一切正常。

现在我不想序列化 Bar 并保持向后兼容性(反正代码中没有引用它)。 NonSerialized 属性似乎就足够了。但是,它只能应用于字段,不能应用于自动属性。所以我尝试了这个:

public class Foo
{
    private IBar _bar;
    [NonSerializable]
    public IBar Bar 
    {
        get { return _bar; }
        set { _bar = value; }
    }
}

令人惊讶的是它运行良好 - 我既可以反序列化旧的 Foos 也可以反序列化新的。

我的问题是:如果这些是序列化的字段并且自动属性的支持字段的名称中可能包含一些非 C# 字符,它怎么可能工作?

换句话说:

Old Foo 的 IBar 字段名(我猜):k__BackingField

新 Foo 的 IBar 字段名称:_bar

显然它们不匹配,那么 BinaryFormatter 如何克服这个问题?

【问题讨论】:

  • 当您说该属性从未在代码中引用时,这是否意味着它始终为null?如果是这样,为什么它可以反序列化二进制不兼容的答案是它实际上从来没有必要。
  • 我不够精确。该属性在构造函数中分配了一个值。它从未在其他地方引用过。坦率地说,它应该从 Foo 中删除。
  • 您的“旧”代码在语法上是错误的——请指定属性名称,因为它几乎肯定会影响行为。

标签: c# deserialization .net-4.5 binaryformatter binary-serialization


【解决方案1】:

我认为你的例子有些奇怪。 BinaryFormatter 不应该能够处理这个(据我所知,除非我怀疑在 4.5 中对此进行了更改),这就是为什么如果需要向后兼容使用它是非常危险的。您确定该值是从旧版本序列化并反序列化到新版本吗?你能验证反序列化的数据是否匹配,并且不为空?

有关验证其不工作的程序的完整示例,请参见此处。 http://www.infragistics.com/community/blogs/josh_smith/archive/2008/02/05/automatic-properties-and-the-binaryformatter.aspx

您不会看到任何异常,但名为 xyz__backingfield 的字段中的旧值将丢失,并在新类中替换为默认值。

如果您想向后兼容,请避免使用自动属性,否则您很快就会陷入困境。事实上,这并不重要,因为默认(自动)模式下的 BinaryFormatter 只有在您想在同一应用程序中序列化对象并再次反序列化它们时才真正有用,例如复制和粘贴或类似操作。在这种情况下,您没有版本控制问题,因为执行序列化和反序列化的代码将是相同的。

要使序列化向后兼容而不失去理智,请确保您完全控制架构。 DataContractSerializer、Json.NET 或协议缓冲区(例如 protobuf-net)是很有可能避免麻烦的序列化程序的好例子。

作为最后一种可能性,您可以实现 ISerializable 并使用 BinaryFormatter 的字典存储,但是无论如何您都会遇到手动滚动序列化的所有缺点。

在旁注中,如果您想将属性应用于支持字段,请尝试 [field:AttriuteType],这对于将事件的支持字段标记为非序列化非常有用。

【讨论】:

  • 感谢您的回复。不幸的是,切换到任何其他序列化程序为时已晚。我必须使用 BinaryFormatter 解决方法,并且有时间(将来)完全摆脱 BinarySerialization。
猜你喜欢
  • 2017-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-13
  • 1970-01-01
  • 1970-01-01
  • 2010-11-08
  • 2014-01-04
相关资源
最近更新 更多