JsonConvert.Deserializer 索引问题

Pra*_*tra 2 c# stack json.net

在 C# 中玩堆栈集合时,我遇到了以下问题。正是我不确定为什么会发生这种情况。请说明原因和解决方案的替代方案。

问题 -

具有 Stack 作为属性的类。例如,将该类命名为 Progress。T 是 Item 类类型。

现在,每当用户取得任何进展时,我们都会将其存储在堆栈中。如果用户在两者之间离开,那么下次我们将从该阶段从堆栈中查看该项目。下面的代码片段将给出正在尝试的内容的想法......

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<Progress>(jsonString);

            temp.Items.Push(new Item { PlanID = null, PlanName = "Plan B" });

            jsonString = JsonConvert.SerializeObject(temp);
            temp = JsonConvert.DeserializeObject<Progress>(jsonString);

            temp.Items.Push(new Item { PlanID = null, PlanName = "Plan C" });

            jsonString = JsonConvert.SerializeObject(temp);
            temp = JsonConvert.DeserializeObject<Progress>(jsonString);

            WriteLine(temp.Items.Peek().PlanName);

            ReadLine();
        }
    }

    class Progress
    {
        public Stack<Item> Items { get; set; }

        public Progress()
        {
            Items = new Stack<Item>();
        }
    }

    class Item
    {
        public string PlanID { get; set; }

        public string PlanName { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在这条线 -

WriteLine(temp.Items.Peek().PlanName);
Run Code Online (Sandbox Code Playgroud)

应该回来

C计划

但它正在返回

B计划

因此,为什么要更改索引,任何线索或指针都会有所帮助。

dbc*_*dbc 5

由于这是 Json.NET 的已知行为,如本答案所述,在反序列化以正确顺序推送项目的堆栈时,可以使用自定义JsonConverter

以下通用转换器可Stack<T>用于任何T

/// <summary>
/// Converter for any Stack<T> that prevents Json.NET from reversing its order when deserializing.
/// </summary>
public class StackConverter : JsonConverter
{
    // Prevent Json.NET from reversing the order of a Stack<T> 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<T>(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var list = serializer.Deserialize<List<T>>(reader);
        var stack = existingValue as Stack<T> ?? (Stack<T>)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();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将其添加到JsonSerializerSettings反序列化时更正堆栈的顺序:

var settings = new JsonSerializerSettings { Converters = new[] { new StackConverter() } };
var jsonString = JsonConvert.SerializeObject(progress, settings);
var temp = JsonConvert.DeserializeObject<Progress>(jsonString, settings);
Run Code Online (Sandbox Code Playgroud)

或者Stack<T>直接用标记属性[JsonConverter(typeof(StackConverter))]

class Progress
{
    [JsonConverter(typeof(StackConverter))]
    public Stack<Item> Items { get; set; }

    public Progress()
    {
        Items = new Stack<Item>();
    }
}
Run Code Online (Sandbox Code Playgroud)