gpt4 book ai didi

使用 protobuf-net 序列化通用树

转载 作者:行者123 更新时间:2023-12-02 02:05:55 25 4
gpt4 key购买 nike

我尝试使用各种对象(int、bool、列表、字典等)构建二叉树并对其进行序列化/反序列化。

使用二进制格式化程序序列化它进展顺利,但使用 protobufnet 我遇到了错误。

我不知道问题是否出在树的实现上,或者是使用了protobuf-net。

任何答案都会帮助我
谢谢

编辑

我尝试了在网络中找到的两个版本的树代码

第一个版本 Tree data structure in C#

第二版 http://msdn.microsoft.com/en-us/library/ms379572.aspx

两个版本中的T都是object。

我得到的错误:找不到合适的默认对象编码

最佳答案

要使用 protobuf 进行序列化,需要一些有关如何映射成员的必要数据 - 请注意,每个成员本身必须对 protobuf 有意义,或者必须是某种列表。

如果您可以显示您正在使用的确切树,我可以提供更多帮助,例如:

    [ProtoContract]
class Node<T>
{
[ProtoMember(1)]
public T Value { get; set; }
[ProtoMember(2, DataFormat= DataFormat.Group)]
public List<Node<T>> Children { get { return children; } }
private readonly List<Node<T>> children = new List<Node<T>>();
}

应该可以很好地序列化。必要的数据也可以在运行时在“v2”中提供。

<小时/>

部分基于电子邮件对话,我对模型有了更好的理解,我看到的重要变化是:

  • 值字段必须注释以进行序列化
  • 该类必须带有注释
  • 必须有一个无参数构造函数
  • 必须有一些东西可以用来添加和枚举子列表

最后一个很有趣;我深思熟虑后决定不要求全额IList/IList<T>那里 - 它所需要的只是 IEnumerable<T>和一个Add(T)方法,这样我就可以添加一个仅出于序列化目的而存在的私有(private)包装对象。

因此,根据电子邮件内容:

using System;
using System.Collections.Generic;
using ProtoBuf;


static class Program
{
static void Main()
{
var tree = new NTree<int>(1);
tree.addChild(2);
var child = tree.addChild(3);
tree.addChild(4);
child.addChild(5);
child.addChild(6).addChild(7);


var clone = Serializer.DeepClone(tree);
DrawTree(tree);
Console.WriteLine();
Console.WriteLine();
DrawTree(clone);
}
static void DrawTree<T>(NTree<T> tree, int depth = 0)
{
var prefix = new string('\t', depth++);
Console.WriteLine(prefix + tree.Data);
foreach (var child in tree.Children) DrawTree(child, depth);
}
}

[ProtoContract]
class NTree<T>
{
[ProtoMember(1)]
T data;
LinkedList<NTree<T>> children;
internal T Data { get { return data; } } // added for demo only
internal IEnumerable<NTree<T>> Children { get { return children; } }// added for demo only
public NTree(T data)
{
this.data = data;
children = new LinkedList<NTree<T>>();
}

public NTree<T> addChild(T data) // changed just so I can build a tree for the demo
{
var child = new NTree<T>(data);
children.AddFirst(child);
return child;
}

public NTree<T> getChild(int i)
{
foreach (NTree<T> n in children)
if (--i == 0) return n;
return null;
}

private NTree()
{
children = new LinkedList<NTree<T>>();
}

[ProtoMember(2, DataFormat=DataFormat.Group)]
private NodeWrapper WrappedChildren {
get { return new NodeWrapper(children); }
}
private class NodeWrapper:IEnumerable<NTree<T>>
{ // only exists to help with serialization
private readonly LinkedList<NTree<T>> nodes;

public NodeWrapper(LinkedList<NTree<T>> nodes)
{
this.nodes = nodes;
}
public IEnumerator<NTree<T>> GetEnumerator()
{
return nodes.GetEnumerator();
}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return nodes.GetEnumerator();
}
public void Add(NTree<T> child) { nodes.AddLast(child); }
}
}

哪个应该适合大多数人T你扔它,除了 object 。任何不寻常的对象本身可能应该是数据契约。

v2 注释:

  • 您不需要这些属性;都可以在运行时指定
  • 您不需要无参数构造函数(尽管保留一个构造函数可能是最简单的,以使 children 启动变得容易)
  • 列表可以是非通用的,IEnumerableAdd(object) (但必须指定期望的类型)

关于使用 protobuf-net 序列化通用树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5138510/

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