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); 
  • Регистрация пользовательского JsonConverter по всему миру в Json.Net
  • Json.Net: Html Помощник не регенерирует
  • Как сериализовать словарь как часть его родительского объекта с помощью Json.Net
  • Разбор массива JSON с использованием Json.Net
  • Создайте строго типизированный объект c # из объекта json с ID как имя
  • Как вернуть объект JSon
  • Как реализовать пользовательский JsonConverter в JSON.NET для десериализации списка объектов базового classа?
  • Как изменить имена свойств при сериализации с помощью Json.net?
  • Json.NET Отключить десериализацию в DateTime
  • JSON.net сериализуется непосредственно из oledbconnection
  • Заставить JSON.NET включать миллисекунды при сериализации DateTime (даже если компонент ms равен нулю)
  • Давайте будем гением компьютера.