C # Désérialiser un object dérivé et référencé

J’ai un object de type Node. Node.cs

La sérialisation fonctionne lorsque je passe l’appel comme suit:

var nodeSer = JsonConvert.SerializeObject(mynode, Formatting.Indented, new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects }); 

Mon problème est que l’appel suivant ne fonctionne pas.

 var n = JsonConvert.DeserializeObject(nodeSer, new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects, TypeNameHandling = TypeNameHandling.Auto }); 

L’appel provoque l’erreur suivante:

 Newtonsoft.Json.JsonSerializationException: "ISerializable type 'System.Action' does not have a valid constructor. To correctly implement ISerializable a constructor that takes SerializationInfo and StreamingContext parameters should be present. Path 'Size.ValueChanged', line 35, position 5." 

Comment dois-je concevoir l’appel de désérialisation?

Json.NET ne sérialise pas les événements. L’ public event PropertyChangedEventHandler PropertyChanged dans le type de base PropertyChangedBase du référentiel HousePlan ne devrait pas poser de problèmes lors de la (dé) sérialisation.

Cependant, au moins un des types de ce référentiel a un délégué System.Action plutôt qu’un événement à gérer lorsqu’une valeur est BindablePoint , en particulier BindablePoint :

 public class BindablePoint: PropertyChangedBase { public double X { get { return Value.X; } set { Value = new Point(value, Value.Y); } } public double Y { get { return Value.Y; } set { Value = new Point( Value.X, value); } } private Point _value; public Point Value { get { return _value; } set { _value = value; OnPropertyChanged("Value"); OnPropertyChanged("X"); OnPropertyChanged("Y"); if (ValueChanged != null) ValueChanged(); } } // This property is causing problems for Json.NET public Action ValueChanged; } 

La raison pour laquelle un délégué est utilisé à cette fin n’est pas claire. Cependant, System.Action ne peut pas être désérialisé par Json.NET. En effet, sérialiser et désérialiser ces delegates n’a aucun sens car ils sont affectés dans le constructeur de Node :

 public class Node: DiagramObject { public Node() { Size.ValueChanged = RecalculateSnaps; Location.ValueChanged = RecalculateSnaps; } 

Une solution simple consiste à marquer ces propriétés avec [JsonIgnore]

  [JsonIgnore] public Action ValueChanged; 

Une deuxième solution simple consisterait à remplacer le délégué par un événement approprié, que Json.NET va maintenant ignorer:

  public event EventHandler ValueChanged; 

Si, pour une raison quelconque, vous ne pouvez pas modifier ces types, vous pouvez créer un ContractResolver personnalisé qui ignore automatiquement toutes les propriétés de type de délégué:

 public class IgnorePropertiesOfTypeContractResolver : IgnorePropertiesOfTypeContractResolver { // As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons. // http://www.newtonsoft.com/json/help/html/ContractResolver.htm // http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm // "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance." static IgnorePropertiesOfTypeContractResolver instance; static IgnorePropertiesOfTypeContractResolver() { instance = new IgnorePropertiesOfTypeContractResolver(); } public static IgnorePropertiesOfTypeContractResolver Instance { get { return instance; } } public IgnorePropertiesOfTypeContractResolver() : base(new[] { typeof(T) }) { } } ///  /// Contract resolver to ignore properties of any number of given types. ///  public class IgnorePropertiesOfTypeContractResolver : DefaultContractResolver { readonly HashSet toIgnore; public IgnorePropertiesOfTypeContractResolver(IEnumerable toIgnore) { if (toIgnore == null) throw new ArgumentNullException(); this.toIgnore = new HashSet(toIgnore); } protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var property = base.CreateProperty(member, memberSerialization); if (property.PropertyType.BaseTypesAndSelf().Any(t => toIgnore.Contains(t))) { property.Ignored = true; } return property; } } public static class TypeExtensions { public static IEnumerable BaseTypesAndSelf(this Type type) { while (type != null) { yield return type; type = type.BaseType; } } } 

Maintenant sérialiser avec les parameters suivants:

 var settings = new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects, ContractResolver = IgnorePropertiesOfTypeContractResolver.Instance, }; 

La propriété ValueChanged ne sera plus sérialisée ni désérialisée.