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

Posted

技术标签:

【中文标题】Protobuf-net / NetCore2:反序列化忽略带注释的私有字段【英文标题】:Protobuf-net / NetCore2: Deserialization ignores annotated private fields 【发布时间】:2018-02-05 12:33:48 【问题描述】:

编辑:问题出在Nancy。 Protobuf-net(反)序列化标记的私有字段就好了。

我正在运行一个 NetCore 2.0 单元测试项目。即使有 [ProtoMember] 属性,Protobuf-net 似乎也被忽略了私有字段。

[ProtoContract]
internal class Model

    [ProtoMember(1)]
    public int Example  get; private set;  // Works

    [ProtoMember(2)]
    private List<int> _a; // Not deserialized unless made public

    public IEnumerable<int> A => this._a;

    public Model(int example, IEnumerable<int> a)
    
        this.Example = example;
        this._a = a.ToList(); // Copy prevents mutation
    

    private Model() // For deserialization
    
    

我使用了公共IEnumerable&lt;int&gt; 来避免可变性并隐藏实现细节。它由私有 List&lt;int&gt; 支持以允许序列化。但是,protobuf-net 只会de在我公开该字段时对其进行序列化。另一方面,序列化实际上会包含数据,即使该字段是私有的。

这是预期的行为吗?是否有一种干净的方法可以让 protobuf-net 在反序列化时尊重标记的私有字段?

附:对于非集合成员也可以看到相同的行为,但我已经用IEnumerable/List 进行了演示,因为它说明了这种方法的原因。

【问题讨论】:

【参考方案1】:

netcoreapp2.0net45 为目标时,以下内容的工作方式相同(除了输出的第一行)。我很乐意提供帮助,但我需要看到一个失败的例子。我正在使用:

<PackageReference Include="protobuf-net" Version="2.3.6" />

代码:

using System;
using System.Collections.Generic;
using System.Linq;
using ProtoBuf;
[ProtoContract]
internal class Model

    [ProtoMember(1)]
    public int Example  get; private set;  // Works

    [ProtoMember(2)]
    private List<int> _a; // Not deserialized unless made public

    public IEnumerable<int> A => this._a;

    public Model(int example, IEnumerable<int> a)
    
        this.Example = example;
        this._a = a.ToList(); // Copy prevents mutation
    

    private Model() // For deserialization
    
    

static class Program

    static void Main()
    
#if NETCOREAPP2_0
        Console.WriteLine(".NET Core 2.0");
#elif NET45
        Console.WriteLine(".NET 4.5");
#endif
        var obj = new Model(123, new int[]  4, 5, 6 );
        var clone = Serializer.DeepClone(obj);
        Console.WriteLine(clone.Example);
        foreach (var val in clone.A)
        
            Console.WriteLine(val);
        
    

【讨论】:

感谢您的快速回复!你的例子也适用于我。此外,我在我的项目中遇到了确实工作的类似场景。让我隔离损坏的类,看看它在测试应用程序中是否仍然出现故障...... 当我无法重现该问题时,我开始研究围绕序列化发生的事情。原来 protobuf-net 的反序列化工作正常,然后 Nancy 去忽略其模型绑定中的私有字段。这也解释了为什么响应没有问题,因为这只适用于传入的请求。 @MarcGravell 谢谢你的帮助! 我现在已经解决了我的问题,只需使用公共IEnumerable&lt;T&gt;。我还没有意识到 protobuf-net 还支持这个!这部分是因为我最初只尝试了IReadOnlyCollection&lt;T&gt;,它的可数和保证被物化的兄弟。对于像IEnumerable&lt;T&gt; 这样支持这个有用的小界面,您感觉如何? @Timo is 有一些代码支持只读集合类型,但不确定它是否适用于这种情况;坦率地说,有点尴尬 - 列表更容易 ton :) 有趣,我只能让它为 IEnumerable&lt;T&gt; 工作。不过,我还没有看过那段代码。

以上是关于Protobuf-net / NetCore2:反序列化忽略带注释的私有字段的主要内容,如果未能解决你的问题,请参考以下文章

protobuf-net:不正确的线型反序列化 TimeSpan

Protobuf-Net 总是反序列化一个空列表

protobuf-net 反序列化错误 无效标签:0

为啥我不能使用 ProtoBuf-Net 正确反序列化我的对象?

使用 protobuf-net 反序列化不同的列表

protobuf-net:反序列化 Guid 属性的错误线型异常