C# Newtonsoft:如何反序列化包含接口的接口,包含接口,没有Json属性

问题描述 投票:0回答:1

我有以下代码,该代码在最后一行中断,并出现异常“无法创建 DeserializeInterfaces.IC 类型的实例”。如何在不使用任何属性的情况下反序列化:

[JsonProperty(ItemConverterType = typeof(ConcreteConverter<C>))]`  

我无法使用这些属性,因为接口位于不同的项目中,并且我不能在具体类上存在接口的循环依赖关系。

我的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace DeserializeInterfaces
{
  public class CustomInterfaceConverter : JsonConverter
  {
    public override bool CanConvert( Type objectType )
    {
      bool convertible = typeof( IB ).IsAssignableFrom( objectType )
                         || typeof( IC ).IsAssignableFrom( objectType );

      return convertible;
    }

    public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer )
    {
      JObject jsonObject = JObject.Load( reader );
          
      if (objectType.Name == "IB")
      {
        B retVal = jsonObject.ToObject<B>();
        return retVal;
      }
      if (objectType.Name == "IC")
      {
        C retVal = jsonObject.ToObject<C>();
        return retVal;
      }
      // Handle other cases or return a default implementation
      return null;
    }
    public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer )
    {
      throw new NotImplementedException();
    }
  }

  public interface IA
  {
    IB b { get; set; }
  }

  public class A : IA
  {
    public A() { }

    public IB b { get; set; }
  }

  public interface IB
  {
    IC c { get; set; }
  }


  public class B : IB
  {
    public B() { }

    public B( IC pC )
    {
      c = pC;
    }

    public IC c { get; set; }
  }

  public interface IC
  {
    int v { get; set; }
  }

  public class C : IC
  {
    public C() { }

    public C( int pV )
    {
      v = pV;
    }

    public int v { get; set; }
  }

  class Program
  {
    static void Main( string[] args )
    {
      CustomInterfaceConverter jsonConverter = new CustomInterfaceConverter();
      IA a = new A();
      a.b = new B();
      a.b.c = new C();
      a.b.c.v = 1;
      string aSer = JsonConvert.SerializeObject( a );

      A aDeser = JsonConvert.DeserializeObject<A>( aSer, jsonConverter );
    }
  }
}
c# interface nested json.net deserialization
1个回答
0
投票

假设

IA
应始终反序列化为
A
IB
B
IC
C
,您可以使用
InterfaceToConcreteConverter<TInterface, TConcrete>
的三个实例来反序列化您的 JSON,每个接口一个,转换器从这个答案Json.Net - 高性能反序列化到基于接口的数据结构?

public class InterfaceToConcreteConverter<TInterface, TConcrete> : JsonConverter where TConcrete : TInterface
{
    public InterfaceToConcreteConverter()
    {
        // TConcrete should be a subtype of an abstract type, or an implementation of an interface.  If they
        // are identical an infinite recursion could result, so throw an exception.
        if (typeof(TInterface) == typeof(TConcrete))
            throw new InvalidOperationException(string.Format("typeof({0}) == typeof({1})", typeof(TInterface), typeof(TConcrete)));
    }

    public override bool CanConvert(Type objectType) =>objectType == typeof(TInterface);
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => serializer.Deserialize(reader, typeof(TConcrete));
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
}

使用此转换器,您的序列化代码将如下所示:

var settings = new JsonSerializerSettings
{
    Converters = { new InterfaceToConcreteConverter<IA, A>(), 
                  new InterfaceToConcreteConverter<IB, B>(),
                  new InterfaceToConcreteConverter<IC, C>(),}
};

string aSer = JsonConvert.SerializeObject( a, settings );

A aDeser = JsonConvert.DeserializeObject<A>( aSer, settings );

备注:

  • 这个答案取决于每个接口都有且只有一个具体实现这一事实。如果这不正确,您将需要使用某种先前序列化的类型标识符来确定具体类型。

  • 单一责任原则是你的朋友。创建一个通用的接口到具体的转换器并实例化三个实例比为所有接口创建一些综合转换器要容易得多。

    如果您有许多不同的地方需要使用转换器进行序列化或反序列化,您可以创建静态默认设置以供项目范围使用:

    public static class JsonExtensions
    {
        public static JsonSerializerSettings DefaultSettings { get; } =
            new JsonSerializerSettings
            {
                Converters = { new InterfaceToConcreteConverter<IA, A>(), 
                              new InterfaceToConcreteConverter<IB, B>(),
                              new InterfaceToConcreteConverter<IC, C>(),}
            };
    }
    
    A aDeser = JsonConvert.DeserializeObject<A>( aSer, JsonExtensions.DefaultSettings );
    
  • 通过从

    false
    返回
    CanWrite
    ,写入时将使用默认序列化。

演示小提琴在这里

© www.soinside.com 2019 - 2024. All rights reserved.