JsonConvert.Deserializer索引问题
在C#中使用Stack集合时遇到了以下问题。 确切地说,我不确定为什么会这样。 请详细说明解决方案的原因和替代方案。
问题 –
具有Stack作为属性的类。 例如,将类命名为Progress。 T是类型Item。
现在,只要用户取得任何进展,我们将以堆栈forms存储。 如果用户介于两者之间,那么下次我们将从堆栈中查看项目,以便从该阶段开始。 下面的代码片段将介绍正在尝试的内容……
using static System.Console; using System.Collections.Generic; using Newtonsoft.Json; namespace StackCollection { class Program { static void Main(string[] args) { Progress progress = new Progress(); progress.Items.Push(new Item { PlanID = null, PlanName = "Plan A" }); var jsonString = JsonConvert.SerializeObject(progress); var temp = JsonConvert.DeserializeObject(jsonString); temp.Items.Push(new Item { PlanID = null, PlanName = "Plan B" }); jsonString = JsonConvert.SerializeObject(temp); temp = JsonConvert.DeserializeObject(jsonString); temp.Items.Push(new Item { PlanID = null, PlanName = "Plan C" }); jsonString = JsonConvert.SerializeObject(temp); temp = JsonConvert.DeserializeObject(jsonString); WriteLine(temp.Items.Peek().PlanName); ReadLine(); } } class Progress { public Stack Items { get; set; } public Progress() { Items = new Stack(); } } class Item { public string PlanID { get; set; } public string PlanName { get; set; } } }
现在的线 –
WriteLine(temp.Items.Peek().PlanName);
应该回来
计划C.
但它正在回归
B计划
那么,为什么索引被改变,任何线索或指针都会有所帮助。
看起来堆栈被序列化为List。 问题是,在解构堆栈时,这不会保留正确的顺序(项目实际上是以相反的顺序推送)。 以下是此问题的快速解决方法:
using System; using static System.Console; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using Newtonsoft.Json; namespace StackCollection { class Program { static void Main(string[] args) { Progress progress = new Progress(); progress.Items.Push(new Item { PlanID = null, PlanName = "Plan A" }); var jsonString = JsonConvert.SerializeObject(progress); var temp = JsonConvert.DeserializeObject
由于这是Json.NET的已知行为,如本答案所述 ,在反序列化按正确顺序推送项目的堆栈时,可以使用自定义JsonConverter
。
以下通用转换器可与Stack
用于任何T
:
/// /// Converter for any Stack that prevents Json.NET from reversing its order when deserializing. /// public class StackConverter : JsonConverter { // Prevent Json.NET from reversing the order of a Stack when deserializing. // https://github.com/JamesNK/Newtonsoft.Json/issues/971 static Type StackParameterType(Type objectType) { while (objectType != null) { if (objectType.IsGenericType) { var genericType = objectType.GetGenericTypeDefinition(); if (genericType == typeof(Stack<>)) return objectType.GetGenericArguments()[0]; } objectType = objectType.BaseType; } return null; } public override bool CanConvert(Type objectType) { return StackParameterType(objectType) != null; } object ReadJsonGeneric (JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; var list = serializer.Deserialize>(reader); var stack = existingValue as Stack ?? (Stack )serializer.ContractResolver.ResolveContract(objectType).DefaultCreator(); for (int i = list.Count - 1; i >= 0; i--) stack.Push(list[i]); return stack; } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; try { var parameterType = StackParameterType(objectType); var method = GetType().GetMethod("ReadJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); var genericMethod = method.MakeGenericMethod(new[] { parameterType }); return genericMethod.Invoke(this, new object[] { reader, objectType, existingValue, serializer }); } catch (TargetInvocationException ex) { // Wrap the TargetInvocationException in a JsonSerializerException throw new JsonSerializationException("Failed to deserialize " + objectType, ex); } } public override bool CanWrite { get { return false; } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } }
然后将其添加到JsonSerializerSettings
以在反序列化时更正堆栈的顺序:
var settings = new JsonSerializerSettings { Converters = new[] { new StackConverter() } }; var jsonString = JsonConvert.SerializeObject(progress, settings); var temp = JsonConvert.DeserializeObject
或者直接使用[JsonConverter(typeof(StackConverter))]
标记Stack
属性:
class Progress { [JsonConverter(typeof(StackConverter))] public Stack- Items { get; set; } public Progress() { Items = new Stack
- (); } }
如果您尝试调试它,那么您会注意到Stack
反序列化后项目顺序被破坏。
一个月前,JSON.NET GitHub问题跟踪器也提出了同样的问题。
JamesNK的答案:
我担心这是一个Stack的限制。 序列化时返回结果,反序列化时返回相反的顺序。