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

C# 忽略Json.NET序列化中的基类属性,c#,json,serialization,json.net,C#,Json,Serialization,Json.net,我的班级结构如下: [JsonObject] public class Polygon : IEnumerable<Point> { public List<Point> Vertices { get; set; } public AxisAlignedRectangle Envelope { get; set; } } public class AxisAlignedRectangle : Polygon { public double Lef

我的班级结构如下:

[JsonObject]
public class Polygon : IEnumerable<Point>
{
    public List<Point> Vertices { get; set; }
    public AxisAlignedRectangle Envelope { get; set; }
}

public class AxisAlignedRectangle : Polygon {
    public double Left { get; set; }
    ...
}
我希望在序列化AxisAlignedRectangle时完全删除多边形属性。我尝试向AxisAlignedRectangle类添加
DataContractAttribute
(以及相应的
DataMemberAttribute
属性),但多边形的所有属性仍在序列化。这是出乎意料的,因为中有一个例子表明这种方法应该有效

当被序列化的类型为AxisAlignedRectangle时,是否有人知道从结果Json.NET序列化中显式删除(最重要的)信封属性的方法?谢谢。

通过如下定义类,您可以使用:

[JsonObject]
public class Polygon : IEnumerable<Point>
{
    public List<Point> 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;
    }
}
[JsonObject]
公共类多边形:IEnumerable
{
公共列表顶点{get;set;}
公共AxisAlignedRectangle信封{get;set;}
公共虚拟bool ShouldSerializeEnvelope()
{
返回true;
}
}
公共类AxisAlignedRectangle:多边形
{
公共双左{get;set;}
...
公共重写bool ShouldSerializeEnvelope()
{
返回false;
}
}
我已将完整解决方案发布在:

最简单的方法就是用
[JsonObject(MemberSerialization.OptIn)]
装饰AxisAlignedRectangle对象

在一个句子中,它将只序列化用[JsonProperty]属性修饰的属性。 您可以在此处阅读更多:


另一个选项是用装饰多边形属性。

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

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

public class DerivedClassContractResolver : DefaultContractResolver
{
    private Type _stopAtBaseType;

    public DerivedClassContractResolver(Type stopAtBaseType) 
    {
        _stopAtBaseType = stopAtBaseType;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        Type originalType = GetOriginalType(type);
        IList<JsonProperty> defaultProperties = base.CreateProperties(type, memberSerialization);
        List<string> 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
{
    /// <summary>
    /// Gets a list of all public instance properties of a given class type
    /// excluding those belonging to or inherited by the given base type.
    /// </summary>
    /// <param name="type">The Type to get property names for</param>
    /// <param name="stopAtType">A base type inherited by type whose properties should not be included.</param>
    /// <returns></returns>
    public static List<string> GetPropertyNames(Type type, Type stopAtBaseType)
    {
        List<string> propertyNames = new List<string>();

        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;
    }
}

获取我在自己的类上定义的属性,而不获取从epserver.Core.PageData继承的大量属性。注意:如果不使用(EPiServer CMS会使用。)

则不需要
GetOriginalType()
代码此解决方案的问题是,我只想禁用多边形N个子类中的1个子类中的多边形.Envelope序列化。为了让您的建议发挥作用,我必须将Polygon.Envelope标记为virtual,然后在AxisAlignedRectangle中覆盖它,只需添加JSONIGNOREATTRITE。即使这样做有效,我认为标记为答案的解决方案更干净,因为代码清楚地表明,只能更改其成员的序列化,而不能更改其基本行为。ThanksBrillant,拯救了我的一天,
ContractResolver
正是我所需要的,我认为JsonSerializer缺少的。苏汉迪!伟大的解决方案!感谢分享:)从第三方类继承时不起作用。
public class DerivedClassContractResolver : DefaultContractResolver
{
    private Type _stopAtBaseType;

    public DerivedClassContractResolver(Type stopAtBaseType) 
    {
        _stopAtBaseType = stopAtBaseType;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        Type originalType = GetOriginalType(type);
        IList<JsonProperty> defaultProperties = base.CreateProperties(type, memberSerialization);
        List<string> 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
{
    /// <summary>
    /// Gets a list of all public instance properties of a given class type
    /// excluding those belonging to or inherited by the given base type.
    /// </summary>
    /// <param name="type">The Type to get property names for</param>
    /// <param name="stopAtType">A base type inherited by type whose properties should not be included.</param>
    /// <returns></returns>
    public static List<string> GetPropertyNames(Type type, Type stopAtBaseType)
    {
        List<string> propertyNames = new List<string>();

        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)) 
    }));