我有一个Type Node对象。 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."
如何设计反序列化调用?
答案 0 :(得分:2)
Json.NET不会序列化事件,因此PropertyChangedBase
存储库的HousePlan
基类型中的public event PropertyChangedEventHandler PropertyChanged
不应在(反)序列化期间导致问题。
但是,该存储库中至少有一种类型具有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;
}
不清楚为什么代理而不是事件被用于此目的,但Json.NET无法对System.Action
进行反序列化。实际上,序列化和反序列化这些委托是没有意义的,因为它们是在Node
的构造函数中分配的:
public class Node: DiagramObject
{
public Node()
{
Size.ValueChanged = RecalculateSnaps;
Location.ValueChanged = RecalculateSnaps;
}
一个简单的解决方案是使用[JsonIgnore]
[JsonIgnore]
public Action ValueChanged;
第二个简单的解决方案是用适当的事件替换委托,Json.NET现在将忽略该事件:
public event EventHandler ValueChanged;
如果由于某种原因您无法更改这些类型,您可以创建一个custom 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
属性将不再被序列化或反序列化。