JSON.NET – как десериализовать сборку интерфейсных экземпляров?

Я хотел бы сериализовать этот код через json.net:

public interface ITestInterface { string Guid {get;set;} } public class TestClassThatImplementsTestInterface1 { public string Guid { get;set; } } public class TestClassThatImplementsTestInterface2 { public string Guid { get;set; } } public class ClassToSerializeViaJson { public ClassToSerializeViaJson() { this.CollectionToSerialize = new List(); this.CollectionToSerialize.add( new TestClassThatImplementsTestInterface2() ); this.CollectionToSerialize.add( new TestClassThatImplementsTestInterface2() ); } List CollectionToSerialize { get;set; } } 

Я хочу сериализовать / deserialize ClassToSerializeViaJson с json.net. Сериализация работает, но десериализация дает мне эту ошибку:

Newtonsoft.Json.JsonSerializationException: Не удалось создать экземпляр типа ITestInterface. Тип – это интерфейс или абстрактный class и не может быть создан.

Итак, как я могу десериализовать коллекцию List ?

Ниже приведен полный рабочий пример с тем, что вы хотите сделать:

 public interface ITestInterface { string Guid { get; set; } } public class TestClassThatImplementsTestInterface1 : ITestInterface { public string Guid { get; set; } public string Something1 { get; set; } } public class TestClassThatImplementsTestInterface2 : ITestInterface { public string Guid { get; set; } public string Something2 { get; set; } } public class ClassToSerializeViaJson { public ClassToSerializeViaJson() { this.CollectionToSerialize = new List(); } public List CollectionToSerialize { get; set; } } public class TypeNameSerializationBinder : SerializationBinder { public string TypeFormat { get; private set; } public TypeNameSerializationBinder(string typeFormat) { TypeFormat = typeFormat; } public override void BindToName(Type serializedType, out string assemblyName, out string typeName) { assemblyName = null; typeName = serializedType.Name; } public override Type BindToType(string assemblyName, string typeName) { var resolvedTypeName = string.Format(TypeFormat, typeName); return Type.GetType(resolvedTypeName, true); } } class Program { static void Main() { var binder = new TypeNameSerializationBinder("ConsoleApplication.{0}, ConsoleApplication"); var toserialize = new ClassToSerializeViaJson(); toserialize.CollectionToSerialize.Add( new TestClassThatImplementsTestInterface1() { Guid = Guid.NewGuid().ToString(), Something1 = "Some1" }); toserialize.CollectionToSerialize.Add( new TestClassThatImplementsTestInterface2() { Guid = Guid.NewGuid().ToString(), Something2 = "Some2" }); string json = JsonConvert.SerializeObject(toserialize, Formatting.Indented, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, Binder = binder }); var obj = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, Binder = binder }); Console.ReadLine(); } } 

Я нашел этот вопрос, пытаясь сделать это сам. После того, как я выполнил ответ Гарата , меня поразило то, насколько просто он казался. Если бы я просто выполнял метод, который уже передавался, точный тип (как строка), который я хотел создать, почему библиотека не привязывала его автоматически?

Я фактически обнаружил, что мне не нужны какие-либо пользовательские связующие, Json.Net смог сделать именно то, что мне было нужно, если бы я сказал, что это то, что я делаю.

При сериализации:

 string serializedJson = JsonConvert.SerializeObject(objectToSerialize, Formatting.Indented, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects, TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple }); 

При де-сериализации:

 var deserializedObject = JsonConvert.DeserializeObject(serializedJson, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects }); 

Соответствующая документация: параметры сериализации для настроек Json.NET и TypeNameHandling

Я был также удивлен простотой в Garath’s, а также пришел к выводу, что библиотека Json может делать это автоматически. Но я также подумал, что это даже проще, чем ответ Бен Дженкинсона (хотя я вижу, что он был модифицирован разработчиком самой библиотеки json). Из моих тестов все, что вам нужно сделать, это установить TypeNameHandling в Auto, например:

 var objectToSerialize = new List(); // TODO: Add objects to list var jsonString = JsonConvert.SerializeObject(objectToSerialize, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); var deserializedObject = JsonConvert.DeserializeObject>(jsonString, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); 

Используя настройки по умолчанию, вы не можете. JSON.NET не знает, как десериализовать массив. Однако вы можете указать, какой тип конвертера использовать для вашего типа интерфейса. Чтобы узнать, как это сделать, см. Эту страницу: http://blog.greatrexpectations.com/2012/08/30/deserializing-interface-properties-using-json-net/

Вы также можете найти информацию об этой проблеме в этом вопросе SO: литые интерфейсы для десериализации в JSON.NET

Это старый вопрос, но я подумал, что добавлю более подробный ответ (в виде статьи, которую я написал): http://skrift.io/articles/archive/bulletproof-interface-deserialization-in-jsonnet /

TLDR: вместо того, чтобы настраивать Json.NET для встраивания имен типов в сериализованный JSON, вы можете использовать JSON-конвертер, чтобы выяснить, какой class следует десериализовать, используя любую настраиваемую логику.

Это имеет то преимущество, что вы можете реорганизовать свои типы, не беспокоясь о разрыве десериализации.

Почти дубликат ответа Инрего, но он заслуживает дальнейшего объяснения:

Если вы используете TypeNameHandling.Auto тогда он включает только имя типа / сборки, когда это необходимо (т.е. интерфейсы и базовые / производные classы). Итак, ваш JSON чище, меньше, более конкретный.

Что не является одной из основных точек продажи по XML / SOAP?

Я хотел десериализовать JSON, который не был сериализован моим приложением, поэтому мне нужно было указать конкретную реализацию вручную. Я расширил ответ Николая.

Допустим, у нас есть

 public class Person { public ILocation Location { get;set; } } 

и конкретный пример

 public class Location: ILocation { public string Address1 { get; set; } // etc } 

Добавить в этот class

 public class ConfigConverter : JsonConverter { public override bool CanWrite => false; public override bool CanRead => true; public override bool CanConvert(Type objectType) { return objectType == typeof(I); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new InvalidOperationException("Use default serialization."); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jsonObject = JObject.Load(reader); var deserialized = (T)Activator.CreateInstance(typeof(T)); serializer.Populate(jsonObject.CreateReader(), deserialized); return deserialized; } } 

Затем определите свои интерфейсы с помощью атрибута JsonConverter

 public class Person { [JsonConverter(typeof(ConfigConverter))] public ILocation Location { get;set; } } 

Это можно сделать с помощью атрибутов JSON.NET и JsonSubTypes :

 [JsonConverter(typeof(JsonSubtypes))] [JsonSubtypes.KnownSubTypeWithProperty(typeof(Test1), "Something1")] [JsonSubtypes.KnownSubTypeWithProperty(typeof(Test2), "Something2")] public interface ITestInterface { string Guid { get; set; } } public class Test1 : ITestInterface { public string Guid { get; set; } public string Something1 { get; set; } } public class Test2 : ITestInterface { public string Guid { get; set; } public string Something2 { get; set; } } 

и просто:

 var fromCode = new List(); // TODO: Add objects to list var json = JsonConvert.SerializeObject(fromCode); var fromJson = JsonConvert.DeserializeObject>(json); 
  • Разбор массива JSON с использованием Json.Net
  • Web API 2: как вернуть JSON с именами свойств camelCased, на объекты и их под-объекты
  • Исключить свойство из сериализации через пользовательский атрибут (json.net)
  • Дессериализация данных JSON на C # с использованием JSON.NET
  • Сериализация нескольких свойств DateTime в одном classе с использованием разных форматов для каждого из них
  • Сериализация / десериализация пользовательской коллекции с дополнительными свойствами с помощью Json.Net
  • Дезициализация свойств самореференции не работает
  • Регистрация пользовательского JsonConverter по всему миру в Json.Net
  • Deserialize json с известными и неизвестными полями
  • Преобразовать Newtonsoft.Json.Linq.JArray в список определенного типа объекта
  • Уничтожить вложенные JSON в объекты C #
  • Interesting Posts

    Извлечение текста из сканированной книги .PDF

    Почему Path.Combine не правильно конкатенирует имена файлов, которые начинаются с Path.DirectorySeparatorChar?

    Как заставить Thunderbird перезагрузить структуру папок IMAP

    Как разрезать видеофайлы по кадрам

    com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Ошибка связи связи. Программное обеспечение вызвало прерывание соединения: recv failed

    Spring 4 RestController JSON: характеристики недопустимы в соответствии с заголовками запроса «принять»

    Как создать случайное значение BigInteger в Java?

    В Chrome «Очистить данные просмотра» не удаляются файлы cookie для открытых вкладок инкогнито?

    Почему кросс-домен Ajax является проблемой безопасности?

    Изменение имени виртуального рабочего стола в Windows 10

    Как создать пользовательский хром в wpf?

    Экспорт данных в файл Excel

    malloc () против HeapAlloc ()

    Как предотвратить запуск моего приложения в фоновом режиме на iPhone

    JsonMappingException: из токена START_ARRAY

    Давайте будем гением компьютера.