-1

Hi guys just trying to get my head around the following issue. I want to deserialise the Foo class, which contains a list of Bar objects that in turn contain a reference to the Foo object. The Foo object in the Bar object is used to retrieve Num1 to perform, in turn, some internal calculations (to get Num3):

public class Foo
{
    [JsonProperty]
    public double Num1 { get; set; }

    [JsonProperty]
    public List<Bar> Bars { get; set; }
}

public class Bar
{
    [JsonProperty]
    public double Num2 { get; set; }

    [JsonProperty]
    public double Num3 => Foo.Num1 * 2;

    private Foo Foo;

    public Bar(Foo foo, double num2)
    {
        Foo = foo;
        Num2 = num2;
    }
}

If I serialise it like in the example below, it works ok:

        Foo foo = new Foo()
        {
            Num1 = 8,
            Bars = new List<Bar>()
        };

        foo.Bars.Add(new Bar(foo, 3));
        foo.Bars.Add(new Bar(foo, 5));

        string serialised = JsonConvert.SerializeObject(foo);

        // result is {"Num1":8.0,"Bars":[{"Num2":3.0,"Num3":24.0},{"Num2":5.0,"Num3":40.0}]}

However, if I try to deserialise the same string:

        Foo deserialised = (Foo)JsonConvert.DeserializeObject(serialised, typeof(Foo));

The Foo object gets deserialised, but the Num3 property raises the following null reference error:

(new System.Collections.Generic.ICollectionDebugView(deserialised.Bars).Items[1]).Num3' threw an exception of type 'System.NullReferenceException'

This is just a simple example to show the issue that I am having and I think that the reason is because the Bar object in the json has no reference to any Foo object. In reality, "Num1" is a complex object from which I am retrieving other parameters, so I cannot store Num1 in the Bar class.

Is there a clever way to tackle this type of issue?

EDIT:

So, the temporary solution I have found is to modify the above code 1) by adding the setter as suggested by Matt Dillard (and relevant private field _Num3) and 2) by creating a function (CalculateNum3) for the definition of Num3, which gets called in the main routine and updates the value of _Num3. In this way, Num3 is set by a function and whenever either deserialisation or serialisation occur, they act on the Num3 field. Main drawback is the need to call the CalculateNum3 function each time.

public class Bar
{
    [JsonProperty]
    public double Num2 { get; set; }

    private double _Num3;
    [JsonProperty]
    public double Num3
    {
        get
        {
            return _Num3;
        }
        private set
        {
            _Num3 = value;
        }
    }

    public double CalculateNum3()
    {
        _Num3 = Foo.Num1 * Num2;
        return _Num3;
    }

    private Foo Foo;

    public Bar(Foo foo, double num2)
    {
        Foo = foo;
        Num2 = num2;
    }
}

Main code

        Foo foo = new Foo()
        {
            Num1 = 8,
            Bars = new List<Bar>()
        };

        Bar bar1 = new Bar(foo, 3);
        bar1.CalculateNum3();
        Bar bar2 = new Bar(foo, 5);
        bar2.CalculateNum3();

        foo.Bars.Add(bar1);
        foo.Bars.Add(bar2);
gugu917
  • 9
  • 1
  • 5
  • I could not access all functionalities to create a custom contract resolver...maybe because I am using .net core? – gugu917 Oct 04 '18 at 17:02

1 Answers1

0

Your problem is that the Bar.Num3 property has not setter. When deserializing from a string, JSON.NET will create a brand new instance of the Bar class and assign the values from the JSON string into the object. It tries to call a setter for the Num3 property, but there is none.

Matt Dillard
  • 14,677
  • 7
  • 51
  • 61