je5real / protobuf-net

Automatically exported from code.google.com/p/protobuf-net
Other
0 stars 0 forks source link

Exception due to code in default constructor #450

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
The issue refers to the following SO question:

http://stackoverflow.com/questions/25867912/default-constructor-constraints-in-p
rotobuf-net/25868645?noredirect=1#comment40508571_25868645

I am not sure if my use case is allowed, or if it is a real bug.

here is the verbatim copy of the SO question:

I when I run the shown unit test I get an exception `Object does not match 
target type` during protobuf *deserialization*. 

I narrowed the problem down to the default constructor `ContainerForA()`. 

This default constructor initializes the variable `PropA` with an instance of 
`ClassA` during deserialization, as protobuf-net will call the default 
constructor. Afterwards the protobuf deserializer should overwrite this 
property with the serialized instance of `ClassB`. I think at this point the 
exception is thrown.

If I remove the code from the default constructor `ContainerForA()` the test 
seems to work. 

Does protobuf-net have constraints on what you are allowed to do in your 
default constructor? Or is there any other problem with my code?

I am using `protobuf-net portable 2.0.0.668`

    [ProtoContract]
    [ProtoInclude(101, typeof(IBaseB))]
    [ProtoInclude(102, typeof(ClassA))]
    public interface IBaseA { }

    [ProtoContract]
    [ProtoInclude(103, typeof(ClassB))]
    public interface IBaseB : IBaseA { }

    [ProtoContract]
    public class ClassA : IBaseA
    {
        [ProtoMember(1)]
        public int PropA { get; set; }
    }

    [ProtoContract]
    public class ClassB : IBaseB
    {
        [ProtoMember(2)]
        public string PropB { get; set; }
    }

    [ProtoContract]
    public class ContainerForA
    {
        [ProtoMember(3)]
        public IBaseA InstanceOfA { get; set; }

        public ContainerForA()
        {
            InstanceOfA = new ClassA();
        }
    }

    [TestClass]
    public class ProtoTestBed1
    {
        [TestMethod]
        public void TestProto()
        {
            var containerForA = new ContainerForA()
            {
                InstanceOfA = new ClassB { PropB = "I'm B"}
            };

            var proto = new ProtobufSerializer();
            var bytes = proto.Serialize(containerForA);
            var containerForADeserialized = proto.Deserialize<ContainerForA>(bytes);

            Debug.WriteLine(containerForADeserialized);
        }
    }

Original issue reported on code.google.com by spera...@gmail.com on 17 Sep 2014 at 8:27

GoogleCodeExporter commented 9 years ago
protobuf-net prefers not to replace instances; if a sub-object / collection / 
etc is non-null, it tries very hard to use it rather than reallocate everything 
in the tree. In your case, the simplest fix is probably to simply *not run the 
constructor during deserialization*, which is what somebody already suggested 
on stackoverflow. Does that work?

Original comment by marc.gravell on 17 Sep 2014 at 9:51

GoogleCodeExporter commented 9 years ago
thank you for your reply.

Yes, that makes sense. 
The provided workaround on SO did work for me, I will paste your reply back to 
SO.

I couldn't find a way to close the issue, I guess I am not allowed.

thanks again

Original comment by spera...@gmail.com on 17 Sep 2014 at 9:57

GoogleCodeExporter commented 9 years ago

Original comment by marc.gravell on 17 Sep 2014 at 10:04