0

I have a class that is deserialized using JsonConvert.DeserializeObject. In that object I already had the following:

    public string Name { get; private set; }

    public uint TotalFrames { get; private set; }
    public string AttachedDetachBoneId { get; private set; }
    public string StartingBone { get; set; }

    public uint SyncFrame { get; private set; }
    public uint CycleFrames { get; private set; }
    public uint AttachDetachFrame { get; private set; }

These all get successfully deserialized from string data read from a file. I then added the following:

    public bool ForceAttachedObjectToGround { get; private set; } = true;

This does not get deserialized. I tested a few different cases and got the following results:

  • As Above: not deserialized
  • Remove inline initialization: not deserialized
  • Make setter public: serialized
  • Add `JsonProperty' attribute: serialized

Based on this, I thought perhaps the property type was somehow the issue and adding three new test properties of different types:

    public bool BoolTest { get; private set; }
    public uint UintTest { get; private set; }
    public string StrTest { get; private set; }

These also did not get deserialized, unless I made the setters public or added the JsonProperty. And if I then remove the attribute/make the properties private again, deserialization once again stops working.

What is happening here? How is Json.Net deciding what to deserialize and what not to?

For completeness sake, I do specify my own JsonSerializerSettings. I have TypeNameHandling = TypeNameHandling.Objects, and I specify a custom binder. The binder is not used in this case though.

FlintZA
  • 872
  • 1
  • 11
  • 22
  • Think about it this way, when Json.Net deserializes the class it needs to *set* all the properties, how can it set it if it's private. – Jamie Rees May 15 '18 at 07:09
  • If the properties are only privately settable, then how do they get initialized? In some parameterized constructor? If there is only one constructor, and it is parameterized, and the names of the parameters match the names of the properties, then Json.NET will call it and pass in the JSON values as constructor arguments. – dbc May 15 '18 at 07:18
  • See [Avoiding default constructors and public property setters](https://stackoverflow.com/q/35245256), [How does JSON deserialization in C# work](https://stackoverflow.com/q/41870132) and [JSON.net: how to deserialize without using the default constructor?](https://stackoverflow.com/q/23017716). – dbc May 15 '18 at 07:23
  • @JamieRees it uses reflection to obtain the properties and set them, so it isn't limited by the setter being private. Default behaviour _is_ to ignore private setter properties, but `[JsonProperty]` overrides that. Also, thanks for the constructor references, we use that approach elsewhere in the code :) – FlintZA May 15 '18 at 07:42
  • @dbc the object is intended to only be set from data. That data is exported by a non-C# tool, so this class definition isn't shared by the code that actually generates the values. Thanks for the constructor tip, I was aware of that one, but it's definitely worth having around for anyone else that stumbles on the question. – FlintZA May 15 '18 at 07:44

1 Answers1

0

In this case, the (incredibly obvious) answer was that the serialization behaviour was inherited from an interface the class was implementing.:

public interface IAnimationData
{
    [JsonProperty]
    string Name { get; }

    [JsonProperty]
    uint TotalFrames { get; }

    // etc..
}

public class AnimationData :
    IAnimationData
{
    public string Name { get; private set; }
    public uint TotalFrames { get; private set; }

    // etc
}
FlintZA
  • 872
  • 1
  • 11
  • 22