JsonPropertyAtsortingbute ignoré sur une propriété privée dans une classe dérivée

J’ai un problème avec Json.Net lors de la sérialisation d’objects dérivés, qui ont des propriétés privées. Sth comme

public class Base { [JsonProperty] private ssortingng Type { get { return "Base"; } } } public class Inherited : Base { [JsonProperty] private ssortingng Type { get { return "Inherited"; } } } 

Lorsque je sérialise des instances de Inherited , la propriété Type est toujours définie sur “Base”. La seule façon dont j’ai trouvé ce travail est que la propriété est protégée ou publique et annulée dans la sous-classe.

Pourquoi ça marche comme ça? Est-ce un bug?

On dirait que c’est un comportement voulu de Json.NET. De ReflectionUtils.cs :

  private static void GetChildPrivateProperties(IList initialProperties, Type targetType, BindingFlags bindingAttr) { // fix weirdness with private PropertyInfos only being returned for the current Type // find base type properties and add them to result // also find base properties that have been hidden by subtype properties with the same name while ((targetType = targetType.BaseType()) != null) { foreach (PropertyInfo propertyInfo in targetType.GetProperties(bindingAttr)) { PropertyInfo subTypeProperty = propertyInfo; if (!IsPublic(subTypeProperty)) { // have to test on name rather than reference because instances are different // depending on the type that GetProperties was called on int index = initialProperties.IndexOf(p => p.Name == subTypeProperty.Name); if (index == -1) { initialProperties.Add(subTypeProperty); } else { PropertyInfo childProperty = initialProperties[index]; // don't replace public child with private base if (!IsPublic(childProperty)) { // replace nonpublic properties for a child, but gotten from // the parent with the one from the child // the property gotten from the child will have access to private getter/setter initialProperties[index] = subTypeProperty; } 

C’est là que la liste des propriétés d’un type est générée et, comme vous pouvez le constater, un code préfère intentionnellement les propriétés de même nom dans la classe de base à la classe héritée.

Je ne sais pas pourquoi Json.NET fait cela, vous pouvez signaler un problème et demander pourquoi. En attendant, vous pouvez utiliser un IContractResolver pour empêcher ce comportement de manière sélective:

 [System.AtsortingbuteUsage(AtsortingbuteTargets.Property)] public class JsonPreferDerivedPropertyAtsortingbute : System.Atsortingbute { } public class PreferDerivedPropertyContractResolver : DefaultContractResolver { static PropertyInfo GetDerivedPropertyRecursive(Type objectType, Type stopType, PropertyInfo property) { var parameters = property.GetIndexParameters().Select(info => info.ParameterType).ToArray(); for (; objectType != null && objectType != stopType; objectType = objectType.BaseType) { var derivedProperty = objectType.GetProperty( property.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, property.PropertyType, parameters, null); if (derivedProperty == null) continue; if (derivedProperty == property) return derivedProperty; // No override. if (derivedProperty.GetCustomAtsortingbute() != null) return derivedProperty; } return null; } protected override List GetSerializableMembers(Type objectType) { var list = base.GetSerializableMembers(objectType); for (int i = 0; i < list.Count; i++) { var property = list[i] as PropertyInfo; if (property == null) continue; if (property.DeclaringType != objectType) { var derivedProperty = GetDerivedPropertyRecursive(objectType, property.DeclaringType, property); if (derivedProperty == null || derivedProperty == property) continue; if (derivedProperty != property && (property.GetGetMethod(true) == null || derivedProperty.GetGetMethod(true) != null) && (property.GetSetMethod(true) == null || derivedProperty.GetSetMethod(true) != null)) { list[i] = derivedProperty; } } } return list; } } 

Je recommande de le faire de manière sélective car je ne comprends pas tout à fait pourquoi Json.NET fait ce qu’il fait. Le code ci-dessus remplace uniquement le comportement par défaut des propriétés de classe dérivées avec l'atsortingbut personnalisé JsonPreferDerivedPropertyAtsortingbute appliqué.

Et puis l'utiliser comme:

 public class Base { [JsonProperty] private ssortingng Type { get { return "Base"; } } } public class Inherited : Base { [JsonProperty] [JsonPreferDerivedPropertyAtsortingbute] private ssortingng Type { get { return "Inherited"; } } } public class VeryInherited : Inherited { [JsonProperty] public ssortingng VeryInheritedProperty { get { return "VeryInherited"; } } } public static class TestOverride { public static void Test() { var inherited = new Inherited(); var json1 = JsonConvert.SerializeObject(inherited, Formatting.Indented, new JsonSerializerSettings() { ContractResolver = new PreferDerivedPropertyContractResolver() }); var veryInherited = new VeryInherited(); var json2 = JsonConvert.SerializeObject(veryInherited, Formatting.Indented, new JsonSerializerSettings() { ContractResolver = new PreferDerivedPropertyContractResolver() }); Debug.WriteLine(json1); Debug.WriteLine(json2); } } 

Et les sorties sont:

 { "Type": "Inherited" } 

et

 { "VeryInheritedProperty": "VeryInherited", "Type": "Inherited" }