2

Suppose I have the following class in C#.

class MyClass
{
  [JsonIgnore]
  public Foo Foo { get; set; }

  [JsonProperty("bar")]
  private Bar Bar
  {
    get
    {
      return new Bar()
      {
        Foo = this.Foo,
      }
    }
    set
    {
      this.Foo = value.Foo;
    }
  }
}

Now suppose I create the following instance:

var instance = new MyClass()
{
  Foo = new Foo(){//init properties of Foo};
}

This gets serialized into json correctly, but does not get deserialized. The Bar.set() never seems to get invoked. Any idea why? I've been going over Newtonsoft documentation looking for a clue, but haven't found anything useful yet.

ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
Hiranya Jayathilaka
  • 7,180
  • 1
  • 23
  • 34
  • There would be no Foo in the Bar set as it is ignored – Nkosi Jan 18 '19 at 01:37
  • 1
    The supposed design of this class is questionable based on the provided example. – Nkosi Jan 18 '19 at 01:39
  • It's basically the same issue as the one in [Why are all the collections in my POCO are null when deserializing some valid json with the .NET Newtonsoft.Json component](https://stackoverflow.com/a/32493007/3744182), namely that when populating a **preallocated** reference type object property, Json.NET doesn't call the setter to reset the object back -- since, presumably, it was there to begin with. The workaround of using `ObjectCreationHandling.Replace` should work here also. Or, you could preallocate `Foo` when deserializing, or make `Bar` have a live pointer back to it. – dbc Jan 18 '19 at 01:42
  • Also, what does `Bar` look like? Is it a pure DTO created to introduce some extra level of nesting when serializing `MyClass.Bar` to JSON, or does it have some other responsibility? – dbc Jan 18 '19 at 01:48
  • Yes, Bar is a DTO that provides a level of nesting. I do agree that this class design is not the best. Perhaps, I should the flip things around, and make `Foo` the calculated property. – Hiranya Jayathilaka Jan 18 '19 at 01:54
  • If `Bar` is a pure DTO, then leaving a live link back to `Foo` seems best. Or, make a DTO for `MyClass` and replace the real object with the DTO using a `JsonConverter`. – dbc Jan 18 '19 at 01:55

1 Answers1

0

Based on the comments I came up with the following solution which seems to work.

class MyClass
{
  private Bar _bar = new Bar();

  [JsonIgnore]
  public Foo Foo
  {
     get { return Bar.Foo; }
     set { Bar.Foo = value; }
  }

  [JsonProperty("bar")]
  private Bar Bar
  {
    get
    {
      // there's some validation logic that goes here
      return _bar;
    }
    set
    {
      _bar = value;
    }
  }
}
Hiranya Jayathilaka
  • 7,180
  • 1
  • 23
  • 34