Search code examples
serialization.net-coreprotobuf-net.net-standardprivate-members

Protobuf-net / NetCore2: Deserialization ignores annotated private fields


Edit: The problem was with Nancy. Protobuf-net (de)serializes marked private fields just fine.

I am running a NetCore 2.0 unit test project. Protobuf-net appears to be ignored private fields even though the have the [ProtoMember] attribute.

[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
    {
    }
}

I have used a public IEnumerable<int> to avoid mutability and hide implementation details. It is backed by a private List<int> to allow serialization. However, protobuf-net will only deserialize the field if I make it public. The serialization, on the other hand, will actually include the data even if the field is private.

Is this intended behavior? Is there are a clean way to make protobuf-net honor the marked private field when deserializing?

P.S. The same behavior is seen for non-collection members, but I have demonstrated with IEnumerable/List because it shows the reason for this approach.


Solution

  • The following works identically (apart from the first line of the output) when targetting netcoreapp2.0 or net45. I'd be happy to help, but I'd need to see an example that fails. I'm using:

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

    Code:

    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);
            }
        }
    }