为什么JsonConvert.DeserializeObject不使用指定的JsonConverter?

我编写了一个自定义JsonConverter ,我可以将其分配给JsonSerializerSettings并使用JsonSerializerSettings的generics覆盖:

 var settings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All, Converters = new List() { new MyConverter() } }; var x = JsonConvert.DeserializeObject(input, settings); 

序列化的Json也使用TypeNameHandling.All构建,因此它包含$type字段中的类型信息。

但是,在某些情况下,我不知道序列化了什么类型,并且想要使用DeserializeObject的非generics覆盖。 我期待的是,如果我使用相同的设置和/或转换器,并且Json包含类型信息,引擎将能够正确处理Json。

但似乎我的自定义转换器仅用于Json中的嵌套对象,而不是最高级别 – 尽管每个级别都有$type

我的问题是没有我的自定义转换器,我需要一个类的默认构造函数。 如果我实现它 – 仅用于测试 – 那么DeserializeObject确实返回正确的类型。 但这不是现实生活中的选择:除其他外,自定义转换器使用IOC容器解析所需的实例,然后填充它们。

我错过了什么或者我要求的根本不可能吗?

编辑:因为它是被请求的,下面是一些示例代码。 在这个示例中,反序列化在没有默认构造函数的情况下工作,显然另一个是使用空值(或default(T) )调用的。 但基本问题仍然存在:没有像我期望的那样使用ExampleConverter

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; namespace UnitTests.Serialization { public class Example { public Example() { Console.WriteLine("...Example Default Ctor..."); } public Example(Guid guid) { Console.WriteLine("...Example Ctor: " + guid.ToString()); } public string ExampleProp { get; set; } } public class ExampleConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer){throw new NotImplementedException();} public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer){ Console.WriteLine("...ExampleConverter.ReadJson..."); var result = new Example(Guid.Empty); serializer.Populate(reader, result); return result; } public override bool CanConvert(Type objectType) { return objectType == typeof(Example); } } [TestClass] public class JsonTests { [TestMethod] public void TestDeserializeObject() { var writeSettings = new JsonSerializerSettings() {TypeNameHandling = TypeNameHandling.All,}; var readSettings = new JsonSerializerSettings() {TypeNameHandling = TypeNameHandling.All,Converters = new List() { new ExampleConverter() }}; Console.WriteLine("Creating Example..."); var e1 = new Example(Guid.NewGuid()) { ExampleProp = "some value"}; Console.WriteLine("\nSerializing e1..."); var json = Newtonsoft.Json.JsonConvert.SerializeObject(e1, writeSettings); Console.WriteLine("e1: " + json); Console.WriteLine("\nDeserializing e2 - using DeserializeObject..."); var e2 = Newtonsoft.Json.JsonConvert.DeserializeObject(json, readSettings); Console.WriteLine("e2: " + Newtonsoft.Json.JsonConvert.SerializeObject(e2, writeSettings)); Console.WriteLine("\nDeserializing e3 - using DeserializeObject..."); var e3 = Newtonsoft.Json.JsonConvert.DeserializeObject(json, readSettings); Console.WriteLine("e3: " + Newtonsoft.Json.JsonConvert.SerializeObject(e2, writeSettings)); } } } 

输出:

 Creating Example... ...Example Ctor: d860aa00-4493-4ab0-b681-f0af7b123212 Serializing e1... e1: {"$type":"UnitTests.Serialization.Example, UnitTests","ExampleProp":"some value"} Deserializing e2 - using DeserializeObject... ...ExampleConverter.ReadJson... ...Example Ctor: 00000000-0000-0000-0000-000000000000 e2: {"$type":"UnitTests.Serialization.Example, UnitTests","ExampleProp":"some value"} Deserializing e3 - using DeserializeObject... ...Example Default Ctor... e3: {"$type":"UnitTests.Serialization.Example, UnitTests","ExampleProp":"some value"} 

编辑:我也发现了这一点,但答案似乎是错误的: 如何将JSON反序列化为正确类型的对象,而不必事先定义类型?

对于我的具体用例,以下结果如下:

 public object DeserializeFromTypedString(string input, JsonSerializerSettings settings) { var r = new Regex(@"^\{\s*""\$type"":\s*""([^""]+)"""); var m = r.Match(input); if (m.Success) { var t = Type.GetType(m.Groups[1].Value); return Newtonsoft.Json.JsonConvert.DeserializeObject(input, t, settings); } else { throw new Exception("$type not found!"); } } 

我们的想法是手动解析字符串以获取$type定义,解析类型并使用它来调用相应的DeserializeObject重载。

这对我来说已经足够了,因为在我的特定用例中,我总是将JSON作为字符串(而不是例如Stream或JToken)来表示一个根对象(而不是数组)。 解决方案可以相应调整, 但我仍然希望有更好/更清洁的解决方案

如果我添加方法并在上面的示例中交换相应的行…

 Console.WriteLine("\nDeserializing e3 - using DeserializeFromTypeString..."); var e3 = DeserializeFromTypedString(json, readSettings); 

…输出是(正确):

 Creating Example... ...Example Ctor: b5af2c3f-1c03-49d8-85c6-f3ff60c9f711 Serializing e1... e1: {"$type":"UnitTests.Serialization.Example, UnitTests","Guid":"b5af2c3f-1c03-49d8-85c6-f3ff60c9f711","ExampleProp":"some value"} Deserializing e2 - using DeserializeObject... ...ExampleConverter.ReadJson... ...Example Ctor: 00000000-0000-0000-0000-000000000000 e2: {"$type":"UnitTests.Serialization.Example, UnitTests","Guid":"00000000-0000-0000-0000-000000000000","ExampleProp":"some value"} Deserializing e3 - using DeserializeFromTypedString... ...ExampleConverter.ReadJson... ...Example Ctor: 00000000-0000-0000-0000-000000000000 e3: {"$type":"UnitTests.Serialization.Example, UnitTests","Guid":"00000000-0000-0000-0000-000000000000","ExampleProp":"some value"} 

请注意两个反序列化情况下的ExampleConverter.ReadJsonExample Ctor的输出, ExampleConverter.ReadJson情况表明我的自定义转换器确实在使用。 (我还在实际代码中使用嵌套对象成功测试了它。)