Search code examples
jsonjson.netlinqpadlinq-to-json

Why does dumping this JObject throw an AmbiguousMatchException in LINQPad?


When I run this code in LINQPad using JSON.NET:

var x = JObject.Parse(
@"{
  ""data"" : [ {
    ""id"" : ""bbab529ecefe58569c2b301a"",
    ""name"" : ""Sample Name"",
    ""group"" : ""8b618be8dc064e653daf62f9"",
    ""description"" : ""Sample Name"",
    ""payloadType"" : ""Geolocation"",
    ""contract"" : ""a9da09a7f4a7e7becf961865"",
    ""keepAlive"" : 0
  } ]
}");

x.Dump();

An AmbiguousMatchException is thrown when trying to dump the parsed JSON to LINQPad's output window. Why? As far as I can tell this is perfectly legitimate JSON. http://jsonlint.com/ says it's valid, too.


Solution

  • This is a problem with how .Dump() is implemented most likely.

    If you check the stack trace:

    at System.RuntimeType.GetInterface(String fullname, Boolean ignoreCase)
    at System.Type.GetInterface(String name)
    at UserQuery.Main()
    ...
    

    We can see that the method throwing the exception is System.RuntimeType.GetInterface.

    System.RuntimeType is one of the concrete classes used to represent Type objects when reflection is used at runtime, so let's check Type.GetInterface(String, Boolean) which has this to say:

    AmbiguousMatchException
    The current Type represents a type that implements the same generic interface with different type arguments.

    So it looks like the GetInterface method is called with a type of an interface that is implemented more than once, with different T's or similar.

    To provoke the same error, simply replace x.Dump(); with this:

    var type = x.GetType().GetInterface("System.Collections.Generic.IEnumerable`1", true);
    

    This will throw the same exception.

    Here's a simpler LINQPad example that shows the underlying problem:

    void Main()
    {
        var type = typeof(Problem).GetInterface("System.Collections.Generic.IEnumerable`1", true);
    }
    
    public class Problem : IEnumerable<string>, IEnumerable<int>
    {
        IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<string>)this).GetEnumerator();
        IEnumerator<string> IEnumerable<string>.GetEnumerator() => Enumerable.Empty<string>().GetEnumerator();
        IEnumerator<int> IEnumerable<int>.GetEnumerator() => Enumerable.Empty<int>().GetEnumerator();
    }
    

    This example will throw the exact same exception.


    Conclusion: There is nothing wrong with the Json, nor with Json.Net, this is a problem with how LINQPad tries to figure out the best way to dump the object to the output window.