簡體   English   中英

使用 JSON.net,當在基本 class 上下文中使用時,如何防止序列化派生 class 的屬性?

[英]Using JSON.net, how do I prevent serializing properties of a derived class, when used in a base class context?

給定數據 model:

[DataContract]
public class Parent
{
    [DataMember]
    public IEnumerable<ChildId> Children { get; set; }
}

[DataContract]
public class ChildId
{
    [DataMember]
    public string Id { get; set; }
}

[DataContract]
public class ChildDetail : ChildId
{
    [DataMember]
    public string Name { get; set; }
}

出於實現方便的原因,有時Parent上的ChildId對象實際上是ChildDetail對象。 當我使用 JSON.net 序列化Parent時,它們與所有ChildDetail屬性一起寫出。

Is there any way to instruct JSON.net (or any other JSON serializer, I'm not far enough into the project to be committed to one) to ignore derived class properties when serializing as a base class?

編輯:重要的是,當我直接序列化派生的 class 時,我能夠生成所有屬性。 我只想抑制Parent object 中的多態性。

我使用自定義合同解析器來限制我的哪些屬性要序列化。 這可能會為您指明正確的方向。

例如

/// <summary>
/// json.net serializes ALL properties of a class by default
/// this class will tell json.net to only serialize properties if they MATCH 
/// the list of valid columns passed through the querystring to criteria object
/// </summary>
public class CriteriaContractResolver<T> : DefaultContractResolver
{
    List<string> _properties;

    public CriteriaContractResolver(List<string> properties)
    {
        _properties = properties
    }

    protected override IList<JsonProperty> CreateProperties(
        JsonObjectContract contract)
    {
        IList<JsonProperty> filtered = new List<JsonProperty>();

        foreach (JsonProperty p in base.CreateProperties(contract))
            if(_properties.Contains(p.PropertyName)) 
                filtered.Add(p);

        return filtered;
    }
}

在覆蓋 IList function 中,您可以使用反射來填充僅包含父屬性的列表。

合約解析器應用於您的 json.net 序列化程序。 此示例來自 asp.net mvc 應用程序。

JsonNetResult result = new JsonNetResult();
result.Formatting = Formatting.Indented;
result.SerializerSettings.ContractResolver = 
    new CriteriaContractResolver<T>(Criteria);

我遇到了完全相同的問題,並查找了如何構建我真正正在尋找的 ContractResolver 並且更好地回答了這個問題。 這只會序列化您實際想要序列化的類型 T 的屬性,但是通過此示例,您還可以輕松構建類似的方法:

public class TypeOnlyContractResolver<T> : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        property.ShouldSerialize = instance => property.DeclaringType == typeof (T);
        return property;
    }
}

遇到類似的問題,這是我想出的ContractResolver

public class StrictTypeContractResolver : DefaultContractResolver
{
    private readonly Type _targetType;

    public StrictTypeContractResolver( Type targetType ) => _targetType = targetType;

    protected override IList<JsonProperty> CreateProperties( Type type, MemberSerialization memberSerialization )
        => base.CreateProperties
        (
            _targetType.IsAssignableFrom( type ) ? _targetType : type,
            memberSerialization
        );
}

它僅切斷targetType的后代的屬性,而不影響其基類的屬性或targetType的屬性可能引用的其他類型的屬性。 根據您的需要,這可能會或可能不會對當時提供的其他答案有所改進。

查看這個類似線程中的答案,特別是我的答案中的 IgnorableSerializerContractResolver和更好的lambda 版本

用法:

var jsonResolver = new IgnorableSerializerContractResolver();
// ignore single property
jsonResolver.Ignore(typeof(Company), "WebSites");
// ignore single datatype
jsonResolver.Ignore(typeof(System.Data.Objects.DataClasses.EntityObject));
var jsonSettings = new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, ContractResolver = jsonResolver };

我沒有特別使用過 JSON.Net 所以不肯定這會對你有所幫助。 如果 JSON.Net 從 .Net 序列化系統派生,那么您應該能夠將 [NonSerialized] 屬性添加到您現在希望在基礎 class 中序列化的屬性中。 當您在基礎 class 上調用序列化方法時,序列化應該跳過這些元素。

沒有比較性能影響,但這也是一個可行的解決方案,並且也適用於嵌套/引用的對象。

Derived d = new Derived();           
string jsonStringD = JsonConvert.SerializeObject(d);
Base b = new Base();
JsonConvert.PopulateObject(jsonStringD, b);
string jsonStringB = JsonConvert.SerializeObject(b);

暫無
暫無

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

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