Я написал пользовательский JsonConverter
, который я могу присвоить JsonSerializerSettings
и использовать с общим переопределением JsonConvert.DeserializeObject
, просто отлично:
var settings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.All,
Converters = new List<JsonConverter>() { new MyConverter() }
};
var x = JsonConvert.DeserializeObject<MyType>(input, settings);
Сериализованный Json был построен также с использованием TypeNameHandling.All
, поэтому он содержит информацию о типе в поле $type
.
Однако в некоторых сценариях я не знаю, какой тип был сериализован, и хотел бы использовать неуниверсальное переопределение DeserializeObject
.Я ожидал, что, если я буду использовать те же настройки и / или конвертер, а 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<JsonConverter>() { 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<Example>...");
var e2 = Newtonsoft.Json.JsonConvert.DeserializeObject<Example>(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<Example>...
...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 для объектов правильного типа, без необходимости определять тип заранее?