我有一个类型节点的对象。 Node.cs
拨打电话时,序列化工作如下:
var nodeSer = JsonConvert.SerializeObject(mynode, Formatting.Indented, new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects });
我的问题是以下调用不起作用。
var n = JsonConvert.DeserializeObject<Node>(nodeSer, new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects, TypeNameHandling = TypeNameHandling.Auto });
该调用导致以下错误:
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."
我必须如何设计反序列化调用?
Json.NET不会序列化事件,因此存储库基本类型中的public event PropertyChangedEventHandler PropertyChangedin (序列化)期间不应引起问题。PropertyChangedBaseHousePlan
public event PropertyChangedEventHandler PropertyChanged
PropertyChangedBase
HousePlan
但是,该存储库中的至少一种类型具有一个System.Action委托而不是一个值更改时要处理的事件,尤其是 BindablePoint:
System.Action
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; }
目前尚不清楚为什么为此目的使用委托而不是事件,但是System.ActionJson.NET不能反序列化。实际上,序列化和反序列化这些委托没有任何意义,因为它们在构造函数中分配给Node:
Node
public class Node: DiagramObject { public Node() { Size.ValueChanged = RecalculateSnaps; Location.ValueChanged = RecalculateSnaps; }
一种简单的解决方案是用 [JsonIgnore]
[JsonIgnore]
[JsonIgnore] public Action ValueChanged;
第二种简单的解决方案是用适当的事件替换委托,Json.NET现在将忽略该事件:
public event EventHandler ValueChanged;
如果出于某种原因无法更改这些类型,则可以创建一个自定义ContractResolver,该自定义自动忽略所有委托类型属性:
ContractResolver
public class IgnorePropertiesOfTypeContractResolver<T> : 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<T> instance; static IgnorePropertiesOfTypeContractResolver() { instance = new IgnorePropertiesOfTypeContractResolver<T>(); } public static IgnorePropertiesOfTypeContractResolver<T> Instance { get { return instance; } } public IgnorePropertiesOfTypeContractResolver() : base(new[] { typeof(T) }) { } } /// <summary> /// Contract resolver to ignore properties of any number of given types. /// </summary> public class IgnorePropertiesOfTypeContractResolver : DefaultContractResolver { readonly HashSet<Type> toIgnore; public IgnorePropertiesOfTypeContractResolver(IEnumerable<Type> toIgnore) { if (toIgnore == null) throw new ArgumentNullException(); this.toIgnore = new HashSet<Type>(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<Type> BaseTypesAndSelf(this Type type) { while (type != null) { yield return type; type = type.BaseType; } } }
现在使用以下设置进行序列化:
var settings = new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects, ContractResolver = IgnorePropertiesOfTypeContractResolver<System.Delegate>.Instance, };
该ValueChanged属性将不再被序列化或反序列化。
ValueChanged