Skip to content

ArgumentException when serializing a nested struct #189

Closed

Description

@samcragg

Using 0.8.0 (and 0.9.0-beta1) it looks like there's a problem with serializing nested structures, the following code (which is a simplified example of what we've got) produces this exception:

Exception: ArgumentException
Message: Field '_field' defined on type 'Example.NestedStruct' is not a field on the target object which is of type 'MsgPack.StreamPacker'.
StackTrace:
at System.Reflection.RtFieldInfo.CheckConsistency(Object target)
at System.Reflection.RtFieldInfo.InternalGetValue(Object obj, StackCrawlMark& stackMark)
at System.Reflection.RtFieldInfo.GetValue(Object obj)
at MsgPack.Serialization.EmittingSerializers.Generated.Example_NestedStructSerializer2.PackValueOf_field(Packer , NestedStruct )
at MsgPack.Serialization.PackHelpers.PackToArray[TObject](PackToArrayParameters1& parameter) at MsgPack.Serialization.EmittingSerializers.Generated.Example_NestedStructSerializer2.PackToCore(Packer , NestedStruct ) at MsgPack.Serialization.MessagePackSerializer1.PackTo(Packer packer, T objectTree)
at MsgPack.Serialization.EmittingSerializers.Generated.Example_OuterClassSerializer1.PackValueOfStruct(Packer , OuterClass )
at MsgPack.Serialization.PackHelpers.PackToArray[TObject](PackToArrayParameters1& parameter) at MsgPack.Serialization.EmittingSerializers.Generated.Example_OuterClassSerializer1.PackToCore(Packer , OuterClass ) at MsgPack.Serialization.MessagePackSerializer1.PackTo(Packer packer, T objectTree)
at MsgPack.Serialization.MessagePackSerializer`1.PackSingleObject(T objectTree)
at Example.Program.Main(String[] args)

using System;
using System.Runtime.Serialization;
using MsgPack.Serialization;

namespace Example
{
    [DataContract]
    public struct NestedStruct
    {
        [DataMember]
        private int _field;
    }

    [DataContract]
    public class OuterClass
    {
        [DataMember]
        public NestedStruct Struct { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var context = new SerializationContext();
            context.GetSerializer<OuterClass>().PackSingleObject(new OuterClass());
        }
    }
}

It looks like there's a problem with the generated code, but I'm not sure how to debug that part, sorry. If you change NestedStruct to a class then it works, however.

Activity

  1. samcragg commented on Oct 23, 2016

    @samcragg
    ContributorAuthor

    I've tracked it down to the EmitGetField method of the SerializerBuilder<TContext, TConstruct> class - when invoking the FieldInfo.GetValue method you need to box the value type before passing it in as an argument. That's a simple change and gets it to serialize properly.

    The problem is when it comes to deserializing. Calling FieldInfo.SetValue on a boxed value will change the value of the copied value that was boxed and not the original, i.e.

    MyStruct myStruct = new MyStruct();
    FieldInfo fieldInfo = typeof(MyStruct).GetField("Field");
    fieldInfo.SetValue(myStruct, 123);
    Console.WriteLine(myStruct.Field); // Writes 0, as SetValue received a boxed copy
    

    To get around this I need to use a local:

    object boxed = myStruct;
    fieldInfo.SetValue(boxed, 123);
    fieldInfo = (MyStruct)boxed;
    Console.WriteLine(myStruct.Field); // Writes 123
    

    I'm unsure how I can create the local, however, using the methods in the SerializerBuilder<TContext, TConstruct> class, as if there are more than one field it will try to create two locals with the same name. I also don't want to always create the local as it's rare to be using a struct in the first place. Any idea on what I can do in EmitSetField to declare a local on demand if it's a value type?

  2. yfakariya commented on Oct 25, 2016

    @yfakariya
    Member

    Hi, thank you for reporting.
    Your idea sounds good. You can use DeclareLocal method of SerializerBuilder to avoid local name conflict (depends on TContext implementation).

    If you are writing patch for this, I'll wait for your work.

  3. added a commit that references this issue on Oct 25, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugDetected as bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions