Stack的反序列化<>

时间:2018-03-25 15:54:22

标签: c# serialization json.net

我正在尝试反序列化包含Stack<T>类型属性的对象:

public class Card
{
    public string Name { get; set; }
}

public class Game 
{
   public Stack<Card> Cards { get; } = new Stack<Card>();
}

var game = new Game();
game.Cards.Push(new Card() { Name = "Whatever" });
string ser = JsonConvert.SerializeObject(game);
Game unser = JsonConvert.DeserializeObject<Game>(ser);

当我尝试反序列化先前序列化的对象时,Cards-Property包含堆栈。

缺少的二传手不是问题。当我将Stack<>更改为List<>反序列化工作时:

public class Game 
{
    public List<Card> Cards { get; } = new List<Card>();
}
var game = new Game();
game.Cards.Add(new Card() { Name = "Whatever"));
string ser = JsonConvert.SerializeObject(game);
Game unser = JsonConvert.DeserializeObject<Game>(ser);

因此,使用List<>但不是Stack<>

时同样可以正常工作

所以我的问题是:

  1. 为什么:)
  2. 我可以强制Json.NET使用Stack<>吗?
  3. 正如dbc已经表明的那样,这不是重复的。问题不是条目的错误方向,而是条目完全缺失。

1 个答案:

答案 0 :(得分:2)

使用Json.NET反序列化Stack<T>存在一个已知问题,在

中有解释

报告的行为是反序列化时Stack<T> 颠倒,建议的解决方案是使用自定义JsonConverter,例如显示here的自定义Stack<T>

不幸的是,似乎解决方案不适用于 get-only 堆栈属性,例如你的。即使我为IEnumerable<T>指定了一个工作转换器,get-only属性也会返回空。有关问题的演示,请参阅.Net fiddle #1

那么,为什么会这样呢?由于Stack<T>实现了ICollection<T>而不是Stack<T>JsonArrayContract constructorStack<T>解释为必须通过只读集合构建的只读集合它的parameterized constructor。然后,稍后,当尝试反序列化您的只有预分配的JsonConverter属性时,JsonSerializerInternalReader.CalculatePropertyDetails()决定不能使用预先存在的值(因为它是只读集合)并且因为新的无法设置已分配的集合(因为该属性不可写)JSON属性必须跳过。当然,这并不能解释Stack<T>如果存在的话可能以某种方式填充集合的可能性,即使Json.NET不能。

这对我来说就像一个小虫;您可以report an issue向Newtonsoft表示,即使使用自定义JsonConverter,也无法对仅限Stack<T>属性进行反序列化。

作为保留JsonConverter媒体资源不变性的解决方法,除了为Stack<T>创建自定义Game之外,您还可以为Stack<Card> cards创建参数化构造函数需要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; } } } 参数,并用JsonConstructor标记:

[JsonProperty]

请注意,构造函数参数名称必须与JSON属性名称modulo case相同。

(或者,您可以将该属性设为私有可设置并使用var settings = new JsonSerializerSettings { Converters = { new StackConverter() }, }; var unser = JsonConvert.DeserializeObject<Game>(ser, settings); 标记;但这会破坏不变性的保证。)

然后反序列化,执行:

StackConverter

this answer逐字逐句采用xcodearchive

演示.Net fiddle #2,显示解决方法确实有效。