gpt4 book ai didi

protobuf-net - 使用递归引用理解 ProtoBuf-Net AsReference

转载 作者:行者123 更新时间:2023-12-01 01:26:53 31 4
gpt4 key购买 nike

我正在尝试使用 ProtoMember 中的 AsReference 选项进行递归引用。如果我使用公共(public)构造函数创建 AnOwner 然后序列化/反序列化,AnOwner.Data 变为空。有人可以解释内部发生了什么以及是否支持递归引用?谢谢!

[ProtoContract()]
public class SomeData
{
[ProtoMember(1, AsReference = true)]
public AnOwner Owner;

[ProtoMember(2)]
public string Value;

/// <summary>
/// ProtoBuf deserialization constructor. In fact, Serializer did not complain when this is missing
/// </summary>
private SomeData()
{

}

public SomeData(string value)
{
Value = value;
}
}

[ProtoContract()]
public class AnOwner
{
[ProtoMember(1)]
public SomeData Data;

/// <summary>
/// ProtoBuf deserialization constructor
/// </summary>
private AnOwner()
{

}

public AnOwner(SomeData data)
{
Data = data;
Data.Owner = this;
}
}

编辑:
经过深思熟虑,我设法以这个小演示的形式理解它,我将在这里分享。对于当前的实现(v2 beta),是否为两者都指定 AsReference=true 很重要,无论哪个对象都被指定为 Serializer.Serialize()。
public class Program
{
using System.IO;
using ProtoBuf;
using System;

public static void main();
{
AnOwner owner1, owner2;
AnOwner owner = new AnOwner();
SomeData data = new SomeData();
owner.Data = data;
data.Owner = owner;
string file = "sandbox.txt";

try { File.Delete(file); } catch {}; // Just in case, cos' it felt like some caching was in place.

using (var fs = File.OpenWrite(file)) { Serializer.Serialize(fs, owner); }
using (var fs = File.OpenRead(file)) { owner1 = Serializer.Deserialize<AnOwner>(fs); }
using (var fs = File.OpenRead(file)) { owner2 = Serializer.Deserialize<AnOwner>(fs); }

Console.WriteLine("SomeData.i: {0}, {1}, {2}, {3}", owner1.Data.i, owner1.Data.Owner.Data.i, owner2.Data.i, owner2.Data.Owner.Data.i);
Console.WriteLine("AnOwner.i: {0}, {1}, {2}, {3}", owner1.i, owner1.Data.Owner.i, owner2.i, owner2.Data.Owner.i);

System.Diagnostics.Debug.Assert(owner1 == owner1.Data.Owner, "1. Expect reference same, but not the case.");
System.Diagnostics.Debug.Assert(owner2 == owner2.Data.Owner, "2. Expect reference same, but not the case.");
System.Diagnostics.Debug.Assert(owner1 != owner2, "3. Expect reference different, but not the case.");
}
}

[ProtoContract()]
public class SomeData
{
public static readonly Random RAND = new Random(2);

[ProtoMember(1, AsReference = true)]
public AnOwner Owner;

// Prove that SomeData is only instantiated once per deserialise
public int i = RAND.Next(100);

public SomeData() { }
}

[ProtoContract()]
public class AnOwner
{
public static readonly Random RAND = new Random(3);

[ProtoMember(1, AsReference=true)]
public SomeData Data;

// Prove that AnOwner is only instantiated once per deserialise
public int i = RAND.Next(100);

/// <summary>
/// ProtoBuf deserialization constructor
/// </summary>
public AnOwner() { }
}

最佳答案

基本上,它不是直接序列化 AnOwner,而是使用以下一项或多项序列化一个假的(实际上并不存在)对象:

  • 已经看到的对象的现有键(整数)
  • 新 key
  • 对象本身
  • 类型信息(如果启用 DynamicType)

  • 序列化跟踪对象时,检查内部列表;如果对象在那里(以前见过),则(仅)写入旧 key 。否则,将针对该对象生成并存储一个新 key ,然后写入新 key 和对象。反序列化时,如果找到“新键”,则反序列化对象数据,并根据该键存储新对象(实际上这里的顺序有点复杂,要处理递归)。如果找到“旧键”,则使用内部列表来获取旧的旧对象。

    对于几乎所有对象,比较都是基于引用相等(即使相等被覆盖)。请注意,这对于字符串的工作方式略有不同,它们比较字符串是否相等 - 所以字符串的两个不同实例 "Fred"仍将共享 key 。

    我相信大多数递归方案都受支持,但如果您遇到问题,请告诉我。

    关于protobuf-net - 使用递归引用理解 ProtoBuf-Net AsReference,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7185632/

    31 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com