忽略Json.NET序列化中的基类属性

我有以下类结构:

[JsonObject] public class Polygon : IEnumerable { public List Vertices { get; set; } public AxisAlignedRectangle Envelope { get; set; } } public class AxisAlignedRectangle : Polygon { public double Left { get; set; } ... } 

我正在序列化Polygon类,但是当我这样做时,我得到一个JsonSerializationException ,消息“为属性’Envelope’检测到自引用循环’,类型为’MyNamespace.AxisAlignedRectangle’。” 如果我将[JsonObject(IsReference = true)] ( 如此处所述 )添加到AxisAlignedRectangle,代码运行正常,但我在每个AxisAlignedRectangle实例中得到一个自动分配的$ id字段,并在该实例重新启动时得到一个$ ref字段参考的。 例如,当我序列化多边形时,我得到:

 { Vertices: [ ... ], Envelope: { $id: '1', Left: -5, ... Vertices: [ ... ], Envelope: { $ref: '1' } } } 

我希望在序列化AxisAlignedRectangle时完全删除Polygon属性。 我尝试将DataContractAttribute添加到AxisAlignedRectangle类(以及相应的DataMemberAttribute属性),但Polygon的所有属性仍在序列化。 这是出乎意料的,因为Json.NET文档中有一个示例表明这种方法应该有效。

当序列化的类型是AxisAlignedRectangle时,有没有人知道从生成的Json.NET序列化中显式删除(最重要的)Envelope属性的方法? 谢谢。

您可以使用条件属性序列化 ,通过定义类如下所示:

 [JsonObject] public class Polygon : IEnumerable { public List Vertices { get; set; } public AxisAlignedRectangle Envelope { get; set; } public virtual bool ShouldSerializeEnvelope() { return true; } } public class AxisAlignedRectangle : Polygon { public double Left { get; set; } ... public override bool ShouldSerializeEnvelope() { return false; } } 

我已经发布了完整的解决方案: https : //github.com/thiagoavelino/VisualStudio_C/blob/master/VisualStudio_C/StackOverFlow/ParsingJason/EnvelopePolygonProblem.cs

最简单的方法是使用[JsonObject(MemberSerialization.OptIn)]简单地修饰AxisAlignedRectangle对象。

在一个句子中,它将仅序列化用[JsonProperty]属性修饰的属性。 您可以在这里阅读更多内容: MemberSerialization Enumeration 。

另一个选择是使用JsonIgnoreAttribute类装饰Polygon属性。

我遇到了同样的事情。 如果应始终使用某个属性并且您可以访问包含该属性的类,则JsonIgnoreAttribute是一个很好的解决方案。 但是,如果要确定在序列化时应序列化哪些属性,则可以使用ContractResolver。

这是一个实现,允许您序列化从最派生类开始并在给定基类停止的属性。 在我的例子中,我想序列化我的自定义CMS(EPiServer)页面类型的属性,但不想序列化页面类的所有内置属性。

 public class DerivedClassContractResolver : DefaultContractResolver { private Type _stopAtBaseType; public DerivedClassContractResolver(Type stopAtBaseType) { _stopAtBaseType = stopAtBaseType; } protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) { Type originalType = GetOriginalType(type); IList defaultProperties = base.CreateProperties(type, memberSerialization); List includedProperties = Utilities.GetPropertyNames(originalType, _stopAtBaseType); return defaultProperties.Where(p => includedProperties.Contains(p.PropertyName)).ToList(); } private Type GetOriginalType(Type type) { Type originalType = type; //If the type is a dynamic proxy, get the base type if (typeof(Castle.DynamicProxy.IProxyTargetAccessor).IsAssignableFrom(type)) originalType = type.BaseType ?? type; return originalType; } } public class Utilities { ///  /// Gets a list of all public instance properties of a given class type /// excluding those belonging to or inherited by the given base type. ///  /// The Type to get property names for /// A base type inherited by type whose properties should not be included. ///  public static List GetPropertyNames(Type type, Type stopAtBaseType) { List propertyNames = new List(); if (type == null || type == stopAtBaseType) return propertyNames; Type currentType = type; do { PropertyInfo[] properties = currentType.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); foreach (PropertyInfo property in properties) if (!propertyNames.Contains(property.Name)) propertyNames.Add(property.Name); currentType = currentType.BaseType; } while (currentType != null && currentType != stopAtBaseType); return propertyNames; } } 

这让我做这样的事情:

 JsonConvert.SerializeObject(page, new JsonSerializerSettings() { ContractResolver = new DerivedClassContractResolver(typeof(EPiServer.Core.PageData)) })); 

获取我在我自己的类上定义的属性,而不会获得从EPiServer.Core.PageDatainheritance的大量属性。 注意:如果您没有使用Castle DynamicProxy 项目 (EPiServer CMS可以使用GetOriginalType()则不需要GetOriginalType()代码。