Newtonsoft.json序列化和反序列化base / inheirited类来自共享项目

所以我有两个类,如下所示。 它们都在同一个命名空间和同一个共享项目中。

public class Person{ public string Name{get;set;} } public class EmployedPerson : Person{ public string JobTitle{get;set;} } 

当我将这些项目serilized到rabbitmq时,我将序列化为基类,如下所示:

 JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple, TypeNameHandling = TypeNameHandling.Objects }; JsonConvert.SerializeObject(input, settings) 

但是,当反序列化时,我会遇到问题。 我希望能够执行如下所示的操作,我将反序列化为基类,然后检查它是否是一个非常类型。

类型检查:

 Person person = Deserialize(e.Body, Encoding.Unicode); if (person is EmployedPerson) { logger.LogInformation("This person has a job!"); } 

反序列化设置:

  JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple, TypeNameHandling = TypeNameHandling.Auto }; 

反序列化逻辑:

  private static T Deserialize(byte[] data, Encoding encoding) where T : class { try { using (MemoryStream stream = new MemoryStream(data)) using (StreamReader reader = new StreamReader(stream, encoding)) return JsonSerializer.Create(settings).Deserialize(reader, typeof(T)) as T; } catch (Exception e) { Type typeParameter = typeof(T); logger.LogError(LogEvent.SERIALIZATION_ERROR, e, "Deserializing type {@TypeName} failed", typeParameter.Name); logger.LogInformation(Encoding.UTF8.GetString(data)); return default(T); } } 

结果:上面的代码失败,因为$ type属性包含程序集名称,并且在rabbitmq的每一端,程序集名称不同,因为这些类在共享项目中。

示例错误:

 Newtonsoft.Json.JsonSerializationException: Error resolving type specified in JSON 'Shared.Objects.EmployedPerson, Person.Dispatcher'. Path '$type', line 1, position 75. ---> System.IO.FileNotFoundException: Could not load file or assembly 'Person.Dispatcher, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified. 

谢谢@dbc,根据我的意思,你写一个自定义SerializationBinder的建议是我问题的最佳解决方案。

我在以下位置使用了KnownTypesBinder: https : //www.newtonsoft.com/json/help/html/SerializeSerializationBinder.htm

KnownTypesBinder:

 public class KnownTypesBinder : ISerializationBinder { public IList KnownTypes { get; set; } public Type BindToType(string assemblyName, string typeName) { return KnownTypes.SingleOrDefault(t => t.Name == typeName); } public void BindToName(Type serializedType, out string assemblyName, out string typeName) { assemblyName = null; typeName = serializedType.Name; } } 

将SerializationBinder设置为KnownTypesBinder实例的JsonSerializerSettings用于序列化和反序列化端点。 我可能只需要它用于反序列化结束,但为了保持一致性而将它放在两者中。

 settings = new JsonSerializerSettings { TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple, TypeNameHandling = TypeNameHandling.Objects, SerializationBinder = new KnownTypesBinder() }; 

创建设置对象后,我将其传递给JsonConvert序列化函数。

 JsonConvert.DeserializeObject(Encoding.Unicode.GetString(input), settings) 

另请注意,KnownTypesBinder中的KnownTypes必须预填充您将要反序列化的所有非基本类型。

编辑: 我目前不接受我自己的答案,因为我不知道如何处理复杂类型列表。 例如,如果一个Person有一个List和一个List,当typeName是“List`1”时你会返回什么类型,它可以是一个。

编辑以下版本的KnownTypesBinder解决了与对象列表相关的问题。

 public class KnownTypesBinder: ISerializationBinder { public IList KnownTypes { get; set; } public Type BindToType(string assemblyName, string typeName) { return KnownTypes.SingleOrDefault(t => t.UnderlyingSystemType.ToString() == typeName); } public void BindToName(Type serializedType, out string assemblyName, out string typeName) { assemblyName = null; typeName = serializedType.UnderlyingSystemType.ToString(); } }