JSON.net: comment désérialiser sans utiliser le constructeur par défaut?

J’ai une classe qui a un constructeur par défaut et aussi un constructeur surchargé qui prend un ensemble de parameters. Ces parameters correspondent aux champs de l’object et sont affectés à la construction. À ce stade, j’ai besoin du constructeur par défaut à d’autres fins, donc je voudrais le garder si je le peux.

Mon problème: Si je supprime le constructeur par défaut et que je transmets la chaîne JSON, l’object se désérialise correctement et transmet les parameters du constructeur sans aucun problème. Je finis par récupérer l’object rempli comme je l’escomptais. Cependant, dès que j’ajoute le constructeur par défaut dans l’object, lorsque j’appelle JsonConvert.DeserializeObject(jsontext) les propriétés ne sont plus renseignées.

À ce stade, j’ai essayé d’append de new JsonSerializerSettings(){CheckAdditionalContent = true} à l’appel de désérialisation. cela n’a rien fait.

Une autre note. les parameters du constructeur correspondent exactement aux noms des champs, sauf que les parameters commencent par une lettre minuscule. Je ne pense pas que cela importerait puisque, comme je l’ai mentionné, la désérialisation fonctionne bien avec aucun constructeur par défaut.

Voici un exemple de mes constructeurs:

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

Json.Net préfère utiliser le constructeur par défaut (sans paramètre) sur un object s’il en existe un. S’il existe plusieurs constructeurs et que vous souhaitez que Json.Net utilise un constructeur autre que celui par défaut, vous pouvez append l’atsortingbut [JsonConstructor] au constructeur que vous souhaitez que Json.Net appelle.

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

Il est important que les noms de paramètre du constructeur correspondent aux noms de propriété correspondants de l’object JSON (en ignorant la casse) pour que cela fonctionne correctement. Cependant, vous ne devez pas nécessairement avoir un paramètre constructeur pour chaque propriété de l’object. Pour les propriétés d’object JSON qui ne sont pas couvertes par les parameters du constructeur, Json.Net essaiera d’utiliser les accesseurs de propriété publique (ou les propriétés / champs marqués avec [JsonProperty] ) pour remplir l’object après sa construction.

Si vous ne souhaitez pas append d’atsortingbuts à votre classe ou ne contrôlez pas le code source de la classe que vous tentez de désérialiser, vous pouvez également créer un JsonConverter personnalisé pour instancier et remplir votre object. Par exemple:

 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"]; ssortingng format = (ssortingng)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(); } } 

Ajoutez ensuite le convertisseur à vos parameters de sérialiseur et utilisez les parameters lorsque vous désérialisez:

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

Un peu en retard et pas tout à fait adapté ici, mais je vais append ma solution ici, car ma question avait été fermée en double de celle-ci, et parce que cette solution est complètement différente.

J’avais besoin d’un moyen général pour demander à Json.NET de préférer le constructeur le plus spécifique à un type de structure défini par l’utilisateur, afin de pouvoir omettre les atsortingbuts JsonConstructor qui appendaient une dépendance au projet où chaque structure est définie.

J’ai un peu procédé au reverse engineering et implémenté un résolveur de contrats personnalisé où j’ai remplacé la méthode CreateObjectContract pour append ma logique de création personnalisée.

 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); } } 

Je l’utilise comme ça.

 public struct Test { public readonly int A; public readonly ssortingng B; public Test(int a, ssortingng 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");