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

如何使用Newtonsoft Json.Net反序列化含接口列表的类型

解决Newtonsoft.Json反序列化接口集合的问题

我来帮你搞定这个反序列化的坑!先理清楚你的代码结构和遇到的问题:

你的类层级结构

public class ProxyBotsSnapshotLogEntryDetails : IBotsSnapshotLogEntryDetails 
{ 
    public ICollection<IBotSnapshot> Snapshots { get; set; } 
} 

public class ProxyBotSnapshot : IBotSnapshot 
{ 
    public string Name { get; set; } 
    public ICollection<IBotSnapshotItem> States { get; set; } 
} 

public class ProxyBotSnapshotItem : IBotSnapshotItem 
{ 
    public int Count { get; set; } 
    public IrcBotChannelStateEnum State { get; set; } 
}

对应的接口定义

public interface IBotsSnapshotLogEntryDetails 
{ 
    ICollection<IBotSnapshot> Snapshots { get; set; } 
} 

public interface IBotSnapshot 
{ 
    string Name { get; set; } 
    ICollection<IBotSnapshotItem> States { get; set; } 
} 

public interface IBotSnapshotItem 
{ 
    int Count { get; set; } 
    IrcBotChannelStateEnum State { get; set; } 
}

你遇到的核心问题是:执行var test = JsonConvert.DeserializeObject<ProxyBotsSnapshotLogEntryDetails>(entry.DetailsSerialized);时,Newtonsoft.Json没法直接把JSON数组转换成ICollection<IBotSnapshot>这类接口集合——毕竟接口不能被实例化,序列化器不知道该用哪个具体类来填充数据。

下面给你两种针对性的解决方案:

方案1:给接口集合属性添加特性指定具体实现

我们先写一个通用转换器,用来把接口类型映射到对应的具体实现类:

public class ConcreteTypeConverter<TConcrete> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        // 判断目标类型是否为接口/抽象类,且TConcrete是它的实现类
        return objectType.IsInterface || objectType.IsAbstract;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // 直接反序列化为指定的具体类型
        return serializer.Deserialize<TConcrete>(reader);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // 序列化时直接处理即可
        serializer.Serialize(writer, value);
    }
}

然后修改你的类,给每个接口集合属性加上这个转换器特性:

public class ProxyBotsSnapshotLogEntryDetails : IBotsSnapshotLogEntryDetails 
{ 
    // 指定将ICollection<IBotSnapshot>反序列化为List<ProxyBotSnapshot>
    [JsonConverter(typeof(ConcreteTypeConverter<List<ProxyBotSnapshot>>))]
    public ICollection<IBotSnapshot> Snapshots { get; set; } 
} 

public class ProxyBotSnapshot : IBotSnapshot 
{ 
    public string Name { get; set; } 

    // 指定将ICollection<IBotSnapshotItem>反序列化为List<ProxyBotSnapshotItem>
    [JsonConverter(typeof(ConcreteTypeConverter<List<ProxyBotSnapshotItem>>))]
    public ICollection<IBotSnapshotItem> States { get; set; } 
}

这样再执行反序列化代码,Newtonsoft就明确知道该实例化哪个具体类来填充接口集合了。

方案2:全局配置序列化设置(无需修改类定义)

如果你不想改动现有类的代码,可以在反序列化时通过JsonSerializerSettings全局指定接口对应的具体实现:

var serializerSettings = new JsonSerializerSettings
{
    ContractResolver = new DefaultContractResolver
    {
        ResolveContract = type =>
        {
            // 为每个接口集合类型指定对应的具体实现
            if (type == typeof(ICollection<IBotSnapshot>))
            {
                return base.ResolveContract(typeof(List<ProxyBotSnapshot>));
            }
            if (type == typeof(ICollection<IBotSnapshotItem>))
            {
                return base.ResolveContract(typeof(List<ProxyBotSnapshotItem>));
            }
            return base.ResolveContract(type);
        }
    }
};

// 使用配置好的Settings进行反序列化
var test = JsonConvert.DeserializeObject<ProxyBotsSnapshotLogEntryDetails>(entry.DetailsSerialized, serializerSettings);

这种方式适合需要统一处理多个接口类型的场景,不用给每个属性加特性,灵活性更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:25:13