Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Null propagation operator and Newtonsoft.Json 10.0.3 exception

Tags:

c#

json.net

I have installed "Newtonsoft.Json" version="10.0.3"

and there are two methods:

    public static bool IsNull_yes(dynamic source)
    {
        if (source.x == null || source.x.y == null) return true;
        return false;
    }

    public static bool IsNull_exception(dynamic source)
    {
        if (source.x?.y == null) return true;
        return false;
    }

Then I have program:

        var o = JObject.Parse(@"{  'x': null }");

        if (IsNull_yes(o) && IsNull_exception(o)) Console.WriteLine("OK");

        Console.ReadLine();
  • When program calls IsNull_yes method then result is "true"
  • When program calls IsNull_exception then result is exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: ''Newtonsoft.Json.Linq.JValue' does not contain a definition for 'y''

Is it Newtonsoft.Json or other bug?

like image 848
Oleg Makarenko Avatar asked Oct 18 '22 01:10

Oleg Makarenko


1 Answers

The short answer is that source.x is 'sort of' null.

To see this, change the code as following:

public static bool IsNull_exception(dynamic source)
{
    var h = source.x;  
    Console.WriteLine(object.ReferenceEquals(null, h));   // false
    Console.WriteLine(null == h);                         // false  
    Console.WriteLine(object.Equals(h, null));            // false
    Console.WriteLine(h == null);                         // true

    if (source.x?.y == null) return true;
    return false;
}

You will note that false is written three times, then true. As such, the equality comparison used by dynamic is not the same as that used by object.Equals etc. See @dbc's awesome post for more details.

Unfortunately, since it is not really equal, null propagation doesn't kick in (since null propagation does not use the h == null style comparison).

As such the equivalent IsNull_yes implementation is not your existing code - but something closer to:

public static bool IsNull_yes(dynamic source)
{
    if (null == source.x || source.x.y == null) return true;
    return false;
}

which acts exactly the same way (i.e. throws an exception).

like image 131
mjwills Avatar answered Oct 21 '22 07:10

mjwills