簡體   English   中英

在Json.NET序列化中忽略基類屬性

[英]Ignore Base Class Properties in Json.NET Serialization

我有以下類結構:

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

我正在序列化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(MemberSerialization.OptIn)]簡單地修飾AxisAlignedRectangle對象。

在一個句子中,它將僅序列化用[JsonProperty]屬性修飾的屬性。 您可以在這里閱讀更多內容: MemberSerialization Enumeration

另一個選擇是使用JsonIgnoreAttribute類裝飾Polygon屬性。

您可以使用條件屬性序列化 ,通過定義類如下所示:

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

我發布了完整的解決方案: https//github.com/thiagoavelino/VisualStudio_C/blob/master/VisualStudio_C/StackOverFlow/ParsingJason/EnvelopePolygonProblem.cs

我遇到了同樣的事情。 如果應始終加入某個屬性並且您可以訪問包含該屬性的類,則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;
    }
}

這讓我做這樣的事情:

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

獲取我在我自己的類上定義的屬性,而不會從EPiServer.Core.PageData繼承大量屬性。 注意:如果您沒有使用Castle DynamicProxy 項目 (EPiServer CMS可以使用GetOriginalType()則不需要GetOriginalType()代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM