JSON.net: как десериализовать без использования конструктора по умолчанию?

У меня есть class, который имеет конструктор по умолчанию, а также перегруженный конструктор, который принимает набор параметров. Эти параметры соответствуют полям объекта и назначаются при построении. На данный момент мне нужен конструктор по умолчанию для других целей, поэтому я хотел бы сохранить его, если смогу.

Моя проблема: если я удаляю конструктор по умолчанию и передаю строку JSON, объект десериализуется правильно и передает параметры конструктора без каких-либо проблем. Я в конечном итоге возвращаю объект, заполненный так, как я ожидал. Однако, как только я добавлю конструктор по умолчанию в объект, когда я вызываю JsonConvert.DeserializeObject(jsontext) свойства больше не заполняются.

На этом этапе я попытался добавить new JsonSerializerSettings(){CheckAdditionalContent = true} к вызову десериализации. что ничего не делало.

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

Вот пример моих конструкторов:

  public Result() { } public Result(int? code, string format, Dictionary details = null) { Code = code ?? ERROR_CODE; Format = format; if (details == null) Details = new Dictionary(); else Details = details; } 

Json.Net предпочитает использовать конструктор по умолчанию (без параметров) для объекта, если он есть. Если есть несколько конструкторов, и вы хотите, чтобы Json.Net использовал нестандартный, вы можете добавить [JsonConstructor] к конструктору, который вы хотите вызвать Json.Net.

 [JsonConstructor] public Result(int? code, string format, Dictionary details = null) { ... } 

Важно, чтобы имена параметров конструктора соответствовали соответствующим именам свойств объекта JSON (игнорируя случай), чтобы это работало правильно. Однако необязательно иметь параметр конструктора для каждого свойства объекта. Для тех свойств объекта JSON, которые не охвачены параметрами конструктора, Json.Net будет пытаться использовать общедоступные объекты доступа (или свойства / поля, помеченные [JsonProperty] ), чтобы заполнить объект после его создания.

Если вы не хотите добавлять атрибуты в свой class или иначе не управляете исходным кодом для classа, который вы пытаетесь десериализовать, то другой альтернативой является создание настраиваемого JsonConverter для создания и заполнения вашего объекта. Например:

 class ResultConverter : JsonConverter { public override bool CanConvert(Type objectType) { return (objectType == typeof(Result)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { // Load the JSON for the Result into a JObject JObject jo = JObject.Load(reader); // Read the properties which will be used as constructor parameters int? code = (int?)jo["Code"]; string format = (string)jo["Format"]; // Construct the Result object using the non-default constructor Result result = new Result(code, format); // (If anything else needs to be populated on the result object, do that here) // Return the result return result; } public override bool CanWrite { get { return false; } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } } 

Затем добавьте конвертер в настройки вашего сериализатора и используйте настройки при десериализации:

 JsonSerializerSettings settings = new JsonSerializerSettings(); settings.Converters.Add(new ResultConverter()); Result result = JsonConvert.DeserializeObject(jsontext, settings); 

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

Мне нужен был общий способ проинструктировать Json.NET чтобы предпочесть конкретный конструктор для определенного типа структуры, поэтому я могу опустить атрибуты JsonConstructor которые добавили бы зависимость от проекта, где каждая такая структура определена.

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

 public class CustomContractResolver : DefaultContractResolver { protected override JsonObjectContract CreateObjectContract(Type objectType) { var c = base.CreateObjectContract(objectType); if (!IsCustomStruct(objectType)) return c; IList list = objectType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).OrderBy(e => e.GetParameters().Length).ToList(); var mostSpecific = list.LastOrDefault(); if (mostSpecific != null) { c.OverrideCreator = CreateParameterizedConstructor(mostSpecific); c.CreatorParameters.AddRange(CreateConstructorParameters(mostSpecific, c.Properties)); } return c; } protected virtual bool IsCustomStruct(Type objectType) { return objectType.IsValueType && !objectType.IsPrimitive && !objectType.IsEnum && !objectType.Namespace.IsNullOrEmpty() && !objectType.Namespace.StartsWith("System."); } private ObjectConstructor CreateParameterizedConstructor(MethodBase method) { method.ThrowIfNull("method"); var c = method as ConstructorInfo; if (c != null) return a => c.Invoke(a); return a => method.Invoke(null, a); } } 

Я использую его вот так.

 public struct Test { public readonly int A; public readonly string B; public Test(int a, string b) { A = a; B = b; } } var json = JsonConvert.SerializeObject(new Test(1, "Test"), new JsonSerializerSettings { ContractResolver = new CustomContractResolver() }); var t = JsonConvert.DeserializeObject(json); tAShouldEqual(1); tBShouldEqual("Test"); 
  • Json.NET: десериализация вложенных словарей
  • Альтернативное имя свойства при десериализации
  • JSON.Net: принудительная сериализация всех частных полей и всех полей в подclassах
  • ТипNameHandling предостережение в Newtonsoft Json
  • Дессериализация данных JSON на C # с использованием JSON.NET
  • Линейная сериализация и де-сериализация
  • Удалить дескриптор объекта json в динамический объект с помощью Json.net
  • Как реализовать пользовательский JsonConverter в JSON.NET для десериализации списка объектов базового classа?
  • Уничтожить stream массива json по одному элементу за раз
  • Десериализация дат с форматом dd / mm / yyyy с использованием Json.Net
  • JSON.Net выдает StackOverflowException при использовании
  • Давайте будем гением компьютера.