【问题标题】:How can I "un-JsonIgnore" an attribute in a derived class?如何在派生类中“取消 JsonIgnore”属性?
【发布时间】:2015-04-24 19:11:00
【问题描述】:

我正在使用Newtonsoft's JsonSerializer 序列化一些类。

由于我想在序列化过程中省略我的类的一个字段,我声明如下:

[JsonIgnore]
public int ParentId { get; set; }

这行得通,但我现在面临一个新问题:在派生类中,我希望这个字段出现(并且在这个特定的派生类中出现)。

我一直在查看文档并在 Internet 上寻找一种在子类中覆盖此设置的方法(我想我需要类似 [JsonStopIgnore] 的东西,但我找不到任何接近的东西)。


  • 我有什么办法可以强制JsonSerializer重新拾取这个属性吗?
  • 是否可以将属性显式标记为[JsonIgnore],但在基类中?

【问题讨论】:

    标签: c# .net json json.net jsonserializer


    【解决方案1】:

    “覆盖”[JsonIgnore] 属性行为的唯一方法是使用合同解析器,正如@Yuval Itzchakov 在他的回答中很好地解释的那样。

    但是,还有另一种可能的解决方案可能对您有用:您可以在类中实现ShouldSerializeParentId() 方法来控制ParentId 属性是否被序列化,而不是使用[JsonIgnore] 属性。在基类中,使该方法返回false;然后,重写派生类中的方法以返回true。 (此功能在 Json.Net 中称为 conditional property serialization。)

    public class Base
    {
        public int Id { get; set; }
        public int ParentId { get; set; }
    
        public virtual bool ShouldSerializeParentId()
        {
            return false;
        }
    }
    
    public class Derived : Base 
    { 
        public override bool ShouldSerializeParentId()
        {
            return true;
        }
    }
    

    小提琴:https://dotnetfiddle.net/65sCSz

    【讨论】:

    • 感谢您对我一无所知的机制的解释!虽然有点重,但这可能是一个比使用自定义合约解析器更简单的解决方案来实现相同的结果:)
    • 没问题;很乐意提供帮助。
    • +1 我发现这对于一组有限的自定义行为来说是一个很好的解决方案。如果需要更通用的方法,我可能会使用 ContractResolver 方式。
    【解决方案2】:

    您可以通过创建自定义DefaultContractResolver 并覆盖其CreateProperty 方法来做到这一点。

    例如,给定一个Foo 基和派生的Bar

    public class Foo
    {
        [JsonIgnore]
        public string Name { get; set; }
        public int Age { get; set; }
    }
    
    public class Bar : Foo 
    { }
    

    您可以创建以下合约解析器:

    public class MyTypeContractResolver<T> : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member,
                                                       MemberSerialization
                                                           memberSerialization)
        {
            var property = base.CreateProperty(member, memberSerialization);
    
            property.Ignored = false;
            property.ShouldSerialize = propInstance => property.DeclaringType != typeof (T);
            return property;
        }
    }
    

    这会将所有属性设置为Ignored = false,然后通过给定的谓词分析它们:

    propInstance => property.DeclaringType != typeof (T);
    

    在我们的例子中,这意味着“只有当它们不是 Foo 类型时才应该序列化”(因为 Foo 是 DeclaryingType)。

    然后当你想反序列化时,你将合约解析器的一个实例传递给JsonSerializerSettings

    var bar = new Bar();
    var result = JsonConvert.SerializeObject(bar,
        new JsonSerializerSettings {ContractResolver = new MyTypeContractResolver<Bar>()});
    

    【讨论】:

    • 感谢您对 ContractResolvers 的解释!如果找不到更轻量级的解决方案,我会采用这种方式,至少可以进行彻底的定制。
    • @PLNech 当然可以。这绝对是“最重”的解决方案,但我认为它也是使用 Json.NET 处理它的“正确”方式。
    • 我很庆幸我现在参考了“正确”的方式,如果我发现自己无法使用“懒惰”的方式:P
    【解决方案3】:

    我通过在派生类的属性上使用 new 关键字解决了同样的问题。

    public class Foo
    {
        [JsonIgnore]
        public int ParentId { get; set; }
    }
    
    public class Bar: Foo
    {
        [JsonProperty("ParentId")]
        public new int ParentId { get; set; }
    }
    

    【讨论】:

    • 我不知道为什么会这样,但确实如此。之后我使用 mongoDb 来保存对象,现在我会抛出映射错误......
    • 它对我有用。但我不明白为什么 JsonProperty 在使用 virtual & override 时不起作用
    • new 修饰符告诉编译器替换属性而不是从基类继承它。由于它现在不再继承 JsonIgnore ,它将被序列化。
    【解决方案4】:

    您可以简单地覆盖派生类中的ParentId

    public new int ParentId
    {
        get { return base.ParentId; }
        set { base.ParentId = value; }
    }
    

    【讨论】:

    • 但请注意,任何对基础类的强制转换都将授予对隐藏属性的访问权限!
    • @AndreasNiedermair 是的。但我认为在使用 Newtonsoft JSonSerializer 进行序列化和反序列化期间,它应该可以工作。对于剩下的代码,如果绕过这个属性就可以了。
    【解决方案5】:

    我用幽灵属性解决了同样的问题:

    public class Foo
    {
        [JsonIgnore]
        public int ParentId { get; set; }
    
        [NotMapped]
        public int FooParent { get; set; }
    }
    

    当我想显示这个属性总是隐藏时,我填充它,其他时候它是空的:

    Foos.ForEach(x => x.FooParent = ParentId);
    

    【讨论】:

      猜你喜欢
      • 2022-06-10
      • 1970-01-01
      • 1970-01-01
      • 2017-11-05
      • 1970-01-01
      • 2019-07-14
      • 1970-01-01
      • 2017-08-21
      相关资源
      最近更新 更多