.Net二进制序列化 - 如何限制对象图?

时间:2009-03-18 14:09:55

标签: .net serialization

我有一个对象,我希望尽可能高效地在进程之间进行序列化和分发。对象本身具有对另一个对象的引用,如:

public class Foo
{
    // Unique Identifier:
    public int Id;
    public Bar Bar;
}

public class Bar
{
    // Unique Identifier:
    public int Id;
}

问题是我只想序列化Foo并通过线路运行它。我宁愿不把Bar包含在我通过电线发送的内容中,因为它在另一边是已知的并且发送它会浪费我的“带宽”。

我想到的是:

  1. 在序列化时,我会序列化 Bar(Foo.Bar)的引用 int包含:Bar.Id(这是一个 Bar实例的唯一标识符)

  2. 只有Foo会被发送到 wire(包含int而不是 酒吧财产)。

  3. 在反序列化时,我会得到 int,从a中获取正确的Bar 存储库并将其放入 Foo.Bar属性。

  4. 这是限制被序列化对象图的任务的有效方法吗?有没有更好的方法呢?

3 个答案:

答案 0 :(得分:5)

我不确定我在这里遗失了什么。

只需在您不想序列化的字段上使用NonSerialized属性。

然后查看SerializationSurrogate以在反序列化时修复引用。

我使用类似的方法来二进制序列化LINQ2SQL对象。

更新:

更好的主意(忘记了这一点)。使用OnDeserializedAttribute,这很容易使用。

如果已经加载到内存中,使用Surrogate方法将允许您返回该对象的另一个实例。我使用它(在IronScheme中)来修复对运行时可能存在的盒装值类型的引用。

更新2:

您可以在following file的中间看到ISerializationSurrogate的示例。 (我提前为丑陋道歉)。

答案 1 :(得分:3)

您所描述的内容需要ISerializable(自定义序列化)和常规BinaryFormatter - 但是,protobuf-net可以让您简化(因此您不需要自己处理细节) ,虽然通常会在过程中缩小数据:

[ProtoContract]
public class Foo : ISerializable
{
    // Unique Identifier:
    [ProtoMember(1)]
    public int Id;
    public Bar Bar;

    [ProtoMember(2)]
    private int? BarProxy {
        get {
           if(Bar == null) return null;
           return Bar.Id;
        }
        set {
           if(value == null) { Bar = null; }
           else { // fetch from repository
             Bar = new Bar(); 
             Bar.Id = value;
           }
        }
    }

    public Foo() { }

    void ISerializable.GetObjectData(SerializationInfo info,
           StreamingContext context) {
        Serializer.Serialize(info, this);
    }
    protected Foo(SerializationInfo info, StreamingContext context) {
        Serializer.Merge(info, this);
    }
}

public class Bar
{
    // Unique Identifier:
    public int Id;
}

更简单的设置:

您使用的是什么序列化程序?

  • BinaryFormatter一起,您将不想要的字段标记为[NonSerialized]
  • XmlSerializer一起,将您不想要的成员标记为[XmlIgnore]
  • 使用DataContractSerializer,您只需[DataContract]
  • 标记它们

另外 - 也许考虑protobuf-net;这有一个非常有效的二元机制;比BinaryFormatter

更多

答案 2 :(得分:2)

这听起来很可行,实际上你在Foo上实现了ISerializable接口,它可以控制你如何序列化Foo。

然后你实现相应的构造函数,你就可以访问你保存的状态,并可以将id拉出来。