You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中Stack<T>类型属性的Json反序列化问题咨询

嘿,我知道你遇到Stack反序列化的问题了!咱们来一步步拆解解决它~

你这段代码里,反序列化后Cards属性的元素大概率会出现顺序反转的情况,甚至可能不符合预期?这其实是Json.NET处理Stack的特性导致的:

Stack本身是后进先出的结构,它的枚举顺序是从顶部元素开始往下读的。Json.NET序列化的时候会跟着这个枚举顺序生成数组,但反序列化时,它会把数组里的元素挨个Push进Stack——这就导致了顺序反转:比如你先Push了CardA,再PushCardB,序列化出来的数组是[CardB, CardA],反序列化时先PushCardB,再PushCardA,此时Stack的顶部变成了CardA,和原来的顶部CardB完全相反。

另外,你的Game类里Cards是只读自动属性(只有getter),虽然Json.NET可以往你初始化好的Stack实例里添加元素,但因为Stack的特殊性,还是会踩顺序的坑。

解决方案

方案1:自定义JsonConverter处理Stack(推荐)

写一个自定义转换器,让序列化和反序列化时保持顺序一致。这个转换器会在序列化时把Stack转成List(按实际存储的底部到顶部顺序),反序列化时再把List转成正确顺序的Stack:

public class StackConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Stack<T>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // 把JSON数组反序列化成List
        var list = serializer.Deserialize<List<T>>(reader);
        // 反转List后再创建Stack,保证顺序和原Stack一致
        return new Stack<T>(list.AsEnumerable().Reverse());
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var stack = (Stack<T>)value;
        // 把Stack转成List并反转,让序列化后的数组和Stack实际存储顺序一致
        var list = stack.ToList();
        list.Reverse();
        serializer.Serialize(writer, list);
    }
}

然后给Game类的Cards属性加上转换器标记:

public class Game 
{ 
    [JsonConverter(typeof(StackConverter<Card>))]
    public Stack<Card> Cards { get; } = new Stack<Card>(); 
}

这样序列化和反序列化后,Stack的元素顺序就和原来完全一致了。

方案2:改用List封装Stack行为(简单易维护)

如果不想写自定义转换器,可以把内部存储换成List,对外暴露Stack的操作方法,这样序列化List不会有顺序问题:

public class Game 
{ 
    private readonly List<Card> _cards = new List<Card>();
    
    // 对外提供Stack的核心操作
    public void PushCard(Card card) => _cards.Add(card);
    public Card PopCard() 
    {
        if (_cards.Count == 0) throw new InvalidOperationException("没有剩余卡牌了");
        var card = _cards[_cards.Count - 1];
        _cards.RemoveAt(_cards.Count - 1);
        return card;
    }
    
    // 让Json.NET序列化这个List
    [JsonProperty("Cards")]
    private List<Card> CardsList => _cards;
}

这种方式不需要额外写转换器,避免了Stack序列化的坑,但需要调整类的结构,适合可以修改类定义的场景。

方案3:临时手动转换(适合一次性场景)

如果只是偶尔处理这个对象,也可以在序列化前把Stack转成List,反序列化后再转成Stack,不需要修改类:

// 序列化时:把Stack转成List再序列化
var ser = JsonConvert.SerializeObject(new { Cards = game.Cards.ToList() });

// 反序列化时:先转成List,再反转后Push回Stack
var temp = JsonConvert.DeserializeAnonymousType(ser, new { Cards = new List<Card>() });
var unser = new Game();
foreach (var card in temp.Cards.Reverse())
{
    unser.Cards.Push(card);
}

这种方式灵活,但每次处理都要手动写转换逻辑,适合临时场景。

内容的提问来源于stack exchange,提问作者Ole Albers

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:15:33