JSON.NET cannot handle simple array deserialization?

2.3k views Asked by At

I created a simple class with one field. class Test{int value;}

If I use the "preserve references" feature and set it to "all" (i.e. both objects and arrays), then when I simply serialize an array of Test objects, it gets serialized as a JSON object with a special "$values" member with the array values, along with the expected "$id" property to preserve the array reference. That much is fine, but once again the whole thing breaks on deserialization.

Stepping through the source code, I discovered that simply because the test for "IsReadOnlyOrFixedSize" is true, it sets a flag "createdFromNonDefaultConstructor" to true, which doesn't even make any sense, because although it is a fixed size array, it is created from a default constructor, unless it considers any fixed size array constructor a non-default constructor. The bottom line is that it should be able to handle something so basic, and yet it throws this error: "Cannot preserve reference to array or readonly list, or list created from a non-default constructor".

How can I deserialize a basic array while preserving all references in JSON.NET without getting an error?

2

There are 2 answers

0
ken2k On

Got the same issue, I used List<T> instead of T[] to fix it.

0
tur On

You are most likely missing a call to ToObject(...) and a type cast. This should work:

class Test { public int Value; }

class Program
{
    static void Main(string[] args)
    {
        var array = new Test[2];
        var instance = new Test {Value = 123};

        array[0] = instance;
        array[1] = instance;

        var settings = new JsonSerializerSettings
        {
            PreserveReferencesHandling = PreserveReferencesHandling.All
        };

        string serialized = JsonConvert.SerializeObject(array, settings);

        // Explicitly call ToObject() and cast to the target type
        var deserialized = (Test[]) ((JArray)JsonConvert.DeserializeObject(serialized, settings)).ToObject(typeof(Test[]));

        Debug.Assert(deserialized[0].Value == 123);
    }
}