二进制序列化和自动属性

本文关键字:属性 序列化 二进制 | 更新日期: 2023-09-27 18:01:28

我有一个这样的类:

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

该类用于二进制序列化(BinaryFormatter的标准用法)。IBar的实现被标记为[Serializable],所以一切都可以工作。

现在我不想序列化Bar并保持向后兼容性(无论如何它在代码中没有被引用)。非序列化属性似乎就足够了。但是,它只能应用于字段,而不能应用于自动属性。所以我试着这样做:

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

令人惊讶的是,它工作得很好——我既可以对旧的Foos也可以对新的Foos进行反序列化。

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

换句话说:

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

新Foo的IBar字段名:_bar

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

二进制序列化和自动属性

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

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

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

如果您想向后兼容,请避免使用自动属性,否则您很快就会遇到麻烦。事实上,这并不重要,因为默认(自动)模式下的BinaryFormatter只有在您希望在同一应用程序中对对象进行序列化和反序列化时才真正有用,例如用于copy &粘贴或类似操作。在这种情况下,没有版本问题,因为序列化和反序列化都是相同的代码。

要使序列化向后兼容而不失去理智,请确保您对模式有完全的控制。有机会避免麻烦的序列化器的好例子是DataContractSerializer和Json。. NET或协议缓冲区(例如protobuf-net)。

作为最后一种可能性,您可以实现isserializable并使用BinaryFormatter的字典存储,但这样您就有了手工进行序列化的所有缺点。

顺便说一下,如果你想将属性应用于后备字段,请尝试[field: attributetype],这对于将事件的后备字段标记为非序列化非常有用。