我正在尝试反序列化包含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<>
所以我的问题是:
Stack<>
吗?正如dbc已经表明的那样,这不是重复的。问题不是条目的错误方向,而是条目完全缺失。
答案 0 :(得分:2)
使用Json.NET反序列化Stack<T>
存在一个已知问题,在
JsonConvert.DeserializeObject<Stack<T>>
/JsonConvert.Serialize(Stack<T)
does not work as expected. 报告的行为是反序列化时Stack<T>
颠倒,建议的解决方案是使用自定义JsonConverter
,例如显示here的自定义Stack<T>
。
不幸的是,似乎解决方案不适用于 get-only 堆栈属性,例如你的。即使我为IEnumerable<T>
指定了一个工作转换器,get-only属性也会返回空。有关问题的演示,请参阅.Net fiddle #1。
那么,为什么会这样呢?由于Stack<T>
实现了ICollection<T>
而不是Stack<T>
,JsonArrayContract
constructor将Stack<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,显示解决方法确实有效。