There is a known issue using Json.NET to deserialize Stack<T> which is explained in
The behavior reported is that Stack<T> is reversed on deserialization, and the suggested solution is to use a custom JsonConverter such as the one shown here.
Unfortunately it appears that solution does not work for a get-only stack property such as yours. Even if I specify a working converter for Stack<T> the get-only property comes back empty. See .Net fiddle #1 for a demo of the problem.
So, why does this happen? Because Stack<T> implements IEnumerable<T> but not ICollection<T>, the JsonArrayContract constructor interprets Stack<T> as a read-only collection that must be constructed via its parameterized constructor. Then, later, when attempting to deserialize your get-only, pre-allocated Stack<T> property, JsonSerializerInternalReader.CalculatePropertyDetails() decides the pre-existing value cannot be used (because it's a read-only collection) and since a newly allocated collection cannot be set back (because the property is not writable) the JSON property must be skipped. This, of course, doesn't account for the possibility that a JsonConverter if present might be able to populate the collection somehow, even though Json.NET cannot.
This feels like a bug to me; you might report an issue to Newtonsoft that a get-only Stack<T> property cannot be deserialized even with a custom JsonConverter.
As a workaround that preserves the immutability of your Stack<T> property, in addition to creating a custom JsonConverter for Stack<T>, you can create a parameterized constructor for your Game that takes a Stack<Card> cards argument, and mark it with JsonConstructor:
public class Game
{
public Game() { this.cards = new Stack<Card>(); }
[JsonConstructor]
Game(Stack<Card> cards)
{
this.cards = cards ?? new Stack<Card>();
}
readonly Stack<Card> cards;
public Stack<Card> Cards { get { return cards; } }
}
Note that the constructor argument name must be the same as the JSON property name, modulo case.
(Alternatively, you could make the property be privately settable and mark it with [JsonProperty]; this destroys the guarantee of immutability however.)
Then to deserialize, do:
var settings = new JsonSerializerSettings
{
Converters = { new StackConverter() },
};
var unser = JsonConvert.DeserializeObject<Game>(ser, settings);
Where StackConverter is taken verbatim from this answer.
Demo .Net fiddle #2 showing that the workaround does work.