Protobuf-net 对象图引用完整性
Posted
技术标签:
【中文标题】Protobuf-net 对象图引用完整性【英文标题】:Protobuf-net Object graph reference integrity 【发布时间】:2011-07-06 09:57:02 【问题描述】:protobuf-net ver 2 中有一个简洁的选项,称为 [ProtoMember(2,AsReference=true)]。在大多数情况下,这是一个后续问题:
protobuf-net serializing object graph我开始怀疑无论何时发生序列化/反序列化,是否始终保持引用完整性。当您使用 AsReference 选项时,protobuf-net 是否已经这样做了?
为了说明的目的,我整理了一个基本的代码示例,然后想,“也许我需要从 ORM 世界中借鉴一些想法?”我应该实施身份映射吗?我是否应该以某种方式告诉 protobuf(通过委托?)改为解析对/来自外键值的引用。
我想听到的答案是,protobuf-net 可以通过某种方式保持跨程序集边界的引用完整性,即使类型看起来很像。
但是,为了以防万一,这里有一个替代顺序:
a => 1. 解析对主键 int 的引用,2. 序列化
b => 3. 反序列化,4. 将主键 int 解析为引用
注释/约束:
类是彼此的镜像,但会在每个程序集中重新编译。
无论对象何时序列化,对象图都需要相同。即 A.ref=B(序列化/反序列化)。 C.ref=B(序列化/反序列化)。
讨论示例:
using System;
using System.Collections.Generic;
using ProtoBuf;
namespace protobuf_question
class Program
static void Main(string[] args)
var a = new A() key = 1 ;
var b = new B() A = a, key = 2 ;
[ProtoContract]
public class A
[ProtoMember(1)]
public int key get; set;
[ProtoContract]
public class B
[ProtoMember(1)]
public int key get; set;
[ProtoMember(2,AsReference=true)]
public A A get; set; // a reference
[ProtoContract]
public class IdentityMap<T,TKey>
public static readonly IdentityMap<T,TKey> instance = new IdentityMap<T,TKey>(); // singleton
private Dictionary<string, T> identitySpace get; set;
public IEnumerable<string> GetIdentitySet (/* some criteria */)
// used for serializing with reference safety between assemblies.
throw new NotImplementedException();
public TKey GetKey(T reference)
// map object reference to identity map; return identity.
throw new KeyNotFoundException();
【问题讨论】:
【参考方案1】:我想听到的答案是,protobuf-net 可以通过某种方式保持跨程序集边界的引用完整性,即使类型看起来很像。
是的,可以。当使用AsReference=true
时,它会在内部生成一个与其他任何东西无关的不透明密钥,并在网络上使用它;此密钥基于流的确定性。一切都保持 100% 基于合同。只要合约兼容,是否相同类型、相同进程、相同机器、相同操作系统等都没关系。
唯一的例外是在使用 DynamicType=true
选项时,它将类型元数据刻录到线路中,但 即使 也不需要是 实际类型数据 - 如果您想提供比默认设置更细粒度和可控的内容 (type.AssemblyQualifiedName
),您可以订阅一个事件。如果您使用 DynamicType
,这将允许您在实现之间透明地交换类型。当然,如果你不使用DynamicType
,那么这个问题一开始就不存在。
你的身份地图...我不清楚那里的动机。但要明确一点:现有代码不会尝试识别任何“主键”候选者并仅序列化这些候选者;它会在第一次看到对象时序列化它(并且发明一个键),否则它只会写入它上次组成的键。
【讨论】:
您在“流的确定性本质”上听起来很可靠。我需要一段时间才能意识到我不必担心这个。回复:“身份图”。在 ORM 世界中(例如 nhibernate),一个引用被映射到一个身份(或键)。我没有使用 nhibernate,但这个概念似乎是扩展 protobuf-net 超越感知缺陷的好方法......但看起来我不必这样做,因为你已经想到了一切!再次感谢。 说我们想要在引用上进行某种程度的延迟加载。如果我们稍后通过 proto 检索这个引用的数据,可能我们需要使用你提到的那个事件来重新链接它?我们是否应该从 ProtoMember 合约中排除此类“惰性”引用并手动处理? @sgtz 该事件是针对DynamicType
的情况,而不是参考跟踪;完全不相关。 protobuf 没有任何“惰性”内置,因为它处理单通道单向流。但是,您可以将所需的键等存储为类型上的 常规 数据,并自己处理惰性方面。请注意,支持可选序列化,因此您可以选择 not 序列化未加载的内容(并且接收者必须加载它),或者 选择在你拥有它时对其进行序列化(接收器不需要,因为它会在流中)。
我认为访问 protobuf 生成的密钥会很有用……甚至可以说“在 X 上生成密钥”,即使目前还不需要 X。这可能吗?
@sgtz 目前没有,这会使存储复杂化,因为我需要每种类型的存储桶(即客户 124 与发票 123 不同)。我不排除它,但不:今天不存在。以上是关于Protobuf-net 对象图引用完整性的主要内容,如果未能解决你的问题,请参考以下文章
Protobuf-net“反序列化期间引用跟踪对象更改引用”错误(2)