ProtoBuf-net 序列化 IEnumerable<T>

Posted

技术标签:

【中文标题】ProtoBuf-net 序列化 IEnumerable<T>【英文标题】:ProtoBuf-net serializing IEnumerable<T> 【发布时间】:2011-10-17 12:10:39 【问题描述】:

我正在尝试在我的项目中使用 ProtoBuf-NET(主要是 Silverlight 4 项目)。

我在序列化我的模型集合时遇到了困难,它们都是这样定义的:

private List<T> _itemsSet;
public IEnumerable<T> TSet

    get return _itemsSet;
    set _itemsSet = value == null ? new List<T>() : new List<T>(value);

public void AddT(T item)

    //Do my logic here
    _itemsSet.Add(item);

更新:首先我无法序列化它 - No serializer defined for type: System.Collections.Generic.IEnumerable1[MyType]`。其次,我认为我将无法根据手动和 protobuf-net 源代码分析对其进行反序列化。

    有没有办法扩展 protobuf-net 以向 ProtoMemeber 属性中的外部 Add 方法提供委托? 为什么使用ProtoMember(1, OverwriteList=true) 不起作用?它不应该覆盖集合并且不应该关心Add&lt;T&gt;() 方法吗?为什么不尝试将此属性设置为 T[] 或 List&lt;T&gt; 或任何可分配给 IEnumerable&lt;T&gt; 的集合? 有没有办法提供自定义反射机制来处理 Silverlight 中的私有字段,例如:实现:public interface IReflectable object GetValue(FieldInfo field); void SetValue(FieldInfo field, object value); 来处理私有字段。我已经使用这种方法来处理带有 Db4o 的私有字段:http://community.versant.com/Forums/tabid/98/aft/10881/Default.aspx 除了创建继承的MyTypeCollection&lt;T&gt; : Collection&lt;T&gt;,我还有哪些选择?

【问题讨论】:

您是否尝试过在包含类上实现ISerializable 我已将其归因于 ProtoContract(IEnumerable 通用参数类型) 您可能还会发现Surrogates 很有用。 【参考方案1】:

    目前没有,没有;暴露的类型必须具有(至少)Add 方法。虽然我不反对调查对象本身之外的Add 的可能性,但这很复杂,因为您正在查看不同的“主要”对象(序列与容器)。然而;如果你的 parent 对象实现了IEnumerable&lt;T&gt;(返回_itemsSet.GetEnumerator() 等),那么它会自动找到Add

    我看不到这里的上下文;但是,我怀疑如果没有Add,它仍然不乐意将其视为列表首先。不过,我看到了你的做法,这也许是它可以推理“我可以在这里使用List&lt;T&gt;”的一种方式

    说实话,这不是我调查过的事情。所以:没有

    属性中公开的类型至少必须:实现IEnumerable(尽管首选IEnumerable&lt;T&gt;),并公开Add(T)方法。它不必是 Collection&lt;T&gt; / List&lt;T&gt; / 等等 - 简单地说:它必须(目前)有 some 机制来添加。 IList&lt;T&gt; 是一个务实的选择,但我认为这不是你想要的。

乔纳森是对的,外部阶级的替代品(拥有_itemsSetTSetAddT)也可能是一种选择.

如果存在 only 的外部类具有集合和 add 方法,那么只需添加 : IEnumerable&lt;T&gt; 并将 AddT 重命名为 Add 可能会使其工作。

【讨论】:

我的 IEnumerableT 序列化问题怎么办?我已经使用最新的 protobuf-net 源代码在调试模式下运行我的代码,并且没有 Collection | IEnumerable 处理 ValueMember.cs 中的代码:TryGetCoreSerializer LINE:330 所以我在 ValueMember.cs line:262 处遇到异常。 @Alex 本身IEnumerable&lt;T&gt; 不可序列化,因为它不能稳健地反序列化它。充其量,我可以给你一个更好的错误信息!它可以(我真的非常希望)处理“Collection”——但它需要有一些 API在暴露的类型上Add 的东西。 你打算继续在 protobuf-net 上工作并扩展它吗?什么是项目状态?我希望在现实生活项目中使用它,但在目前的状态下,它对我来说无法使用,认为它仍然比从头开始编写自己的解决方案要好。 @Alex 它正在积极开发和使用中。重新扩展它 - 首先我需要清楚地理解这个问题,一个更完整的例子将有很大帮助。 @G-Mac 我不能指责你的论点;我可以支持这种情况 - 它将在下一次部署中工作【参考方案2】:

我试图偷工减料,将我的模型重用为消息合约,但这实际上是错误的做法。可行的方法是为您的模型创建 DTO 的专用类和转换器,无论如何最好将您的模型与消息分开。

不过,我必须批评 Marc,因为他添加了 ProtoContract 和 ProtoMemeber 属性,通过归因来诱使用户重复使用他们的模型。

【讨论】:

批评可能是件好事,但我很好奇你会让我做什么(在这里也要考虑 XmlSerializer 的属性、DataContractSerializer 的属性等)。碰巧的是,在 v2 中,如果您愿意,一切 都可以在没有属性的情况下完成。如果我能看到一个足以运行的完整场景,我会很乐意提供更多输入(目前,我只有一个类的片段,这不容易理解上下文并提供输入)

以上是关于ProtoBuf-net 序列化 IEnumerable<T>的主要内容,如果未能解决你的问题,请参考以下文章

protobuf-net 如何序列化 DateTime?

使用 protobuf-net 序列化具有接口类型成员的类

protobuf-net 序列化返回空数组

Protobuf-Net:如何序列化 guid?

Protobuf-net / NetCore2:反序列化忽略带注释的私有字段

使用 protobuf-net 反序列化字典