Reputation: 25
I'm trying to deserialise a complex object, which can contain instances of that same class (WorldInstance, which can contain more WorldInstances), but it's throwing this exception and I have no idea why, or how to fix it.
I know this is a bit vague, but I have no idea what information is needed, so I will post anything that is asked of me.
EDIT 1: Here's the entire class I'm trying to serialise. http://pastebin.com/QTNH1HZH
I think it's failing on the discoveredTiles, on line 691, even though it shouldn't be doing anything with that data.
Upvotes: 0
Views: 1368
Reputation: 117016
Your problem is that you are trying to make Json.NET deserialize a get-only array property discoveredTiles
, as is shown in the following simplified version of your class:
public class WorldInstance
{
protected WorldTile[,] m_Tiles;
protected bool[,] m_Discovered;
public WorldInstance(WorldTile[,] tiles)
{
m_Tiles = tiles;
m_Discovered = new bool[m_Tiles.GetLength(0), m_Tiles.GetLength(1)];
}
public WorldTile[,] tiles
{
get
{
return m_Tiles;
}
}
public bool[,] discoveredTiles
{
get
{
return m_Discovered;
}
}
}
public class WorldTile
{
}
This is currently not implemented even if the array is pre-allocated and has the same length as the JSON array, since Json.NET will try to add deserialized items to the pre-allocated array, which is of course impossible. (Note that the tiles
property will get deserialized by passing it to the constructor, matching the JSON property name to the constructor argument name.)
For a 1d array property, the exception thrown explains this problem:
System.NotSupportedException: Collection was of a fixed size.
at System.SZArrayHelper.Add[T](T value)
at Newtonsoft.Json.Utilities.CollectionWrapper`1.Add(T item) in C:\Development\Releases\Json\Working\Newtonsoft.Json\Working-Signed\Src\Newtonsoft.Json\Utilities\CollectionWrapper.cs:line 76
at Newtonsoft.Json.Utilities.CollectionWrapper`1.System.Collections.IList.Add(Object value) in C:\Development\Releases\Json\Working\Newtonsoft.Json\Working-Signed\Src\Newtonsoft.Json\Utilities\CollectionWrapper.cs:line 194
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, String id) in C:\Development\Releases\Json\Working\Newtonsoft.Json\Working-Signed\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:line 2030
But for a 2d array the less illuminating InvalidCastException
is thrown.
You have two workarounds for this problem:
Add a protected constructor to WorldInstance
that includes a bool[,] discoveredTiles
argument and mark it with [JsonConstructor]
, for instance:
[JsonConstructor]
protected WorldInstance(WorldTile[,] tiles, bool[,] discoveredTiles)
{
if (tiles == null || discoveredTiles == null)
throw new ArgumentNullException();
// Ensure the tiles and discoveredTiles arrays have the same sizes
if (tiles.GetLength(0) != discoveredTiles.GetLength(0) || tiles.GetLength(1) != discoveredTiles.GetLength(1))
throw new InvalidOperationException("tiles.GetLength(0) != discoveredTiles.GetLength(0) || tiles.GetLength(1) != discoveredTiles.GetLength(1)");
m_Tiles = tiles;
m_Discovered = discoveredTiles;
}
Note that the parameter name discoveredTiles
must be the same as the corresponding serialized property name.
Add a private or protected setter for discoveredTiles
and mark it with [JsonProperty]
:
[JsonProperty]
public bool[,] discoveredTiles
{
get
{
return m_Discovered;
}
protected set
{
if (value == null)
throw new ArgumentNullException();
// Ensure the tiles and discoveredTiles arrays have the same sizes
if (tiles != null && tiles.GetLength(0) != value.GetLength(0) || tiles.GetLength(1) != value.GetLength(1))
throw new InvalidOperationException("tiles != null && tiles.GetLength(0) != value.GetLength(0) || tiles.GetLength(1) != value.GetLength(1)");
m_Discovered = value;
}
}
Upvotes: 1