C# Newtonsoft.Json:无需Json特性实现嵌套接口反序列化
问题分析与解决方案
核心问题
你的代码在反序列化A类时,调用jsonObject.ToObject<A>()没有传入serializer实例,导致嵌套的IB属性反序列化时无法触发自定义转换器,从而抛出无法创建接口实例的异常。此外,通过类型名称判断不够严谨,建议直接使用typeof进行类型比较。
修改后的完整代码
using System; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace DeserializeInterfaces { public class CustomInterfaceConverter : JsonConverter { public override bool CanConvert(Type objectType) { // 检查是否是目标接口或其实现类 return typeof(IA).IsAssignableFrom(objectType) || typeof(IB).IsAssignableFrom(objectType) || typeof(A).IsAssignableFrom(objectType) || typeof(B).IsAssignableFrom(objectType); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject jsonObject = JObject.Load(reader); // 直接通过typeof判断类型,避免名称字符串的硬编码问题 if (objectType == typeof(IA) || objectType == typeof(A)) { // 必须传入serializer,确保嵌套的IB属性也使用当前转换器 return jsonObject.ToObject<A>(serializer); } if (objectType == typeof(IB) || objectType == typeof(B)) { return jsonObject.ToObject<B>(serializer); } return null; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { // 实现序列化逻辑,直接序列化具体实例 JObject.FromObject(value).WriteTo(writer); } } public interface IA { IB b { get; set; } } public interface IB { int b { get; set; } } public class A : IA { [JsonConstructor] public A() { } public IB b { get; set; } } public class B : IB { [JsonConstructor] public B() { } public B(int pB) { b = pB; } public int b { get; set; } } class Program { static void Main(string[] args) { CustomInterfaceConverter jsonConverter = new CustomInterfaceConverter(); IA a = new A(); a.b = new B(1); string aSer = JsonConvert.SerializeObject(a, jsonConverter); A aDeser = JsonConvert.DeserializeObject<A>(aSer, jsonConverter); Console.WriteLine(aDeser.b.b); // 输出1,验证反序列化成功 } } }
关键改动说明
- 修复嵌套属性反序列化问题:将JObject转换为
A类型时,必须传入serializer参数,确保Json.NET处理A中的IB属性时自动使用自定义转换器,避免接口实例创建异常。 - 优化类型判断逻辑:用
typeof(IA)、typeof(A)等直接比较类型,替代字符串名称判断,避免因类型名称变更或命名空间差异导致的错误。 - 补充序列化实现:完善
WriteJson方法,保证接口类型实例的序列化过程正常工作。
循环引用规避方案
将自定义转换器放在具体实现类所在的项目或独立的通用工具项目中,这样既不会让接口项目依赖具体实现类,也能正常完成反序列化逻辑,彻底避免循环引用问题。
内容的提问来源于stack exchange,提问作者Markus
相关产品推荐
相关产品推荐

