我正在使用 Newtonsoft 的 JsonSerializer 来序列化一些类。
由于我想在序列化过程中省略类的一个字段,因此我将其声明如下:
[JsonIgnore]
public int ParentId { get; set; }
这有效,但我现在面临一个新问题:在派生类中,我希望出现此字段(并且仅在这个特定的派生类中这样做)。
我一直在浏览文档和互联网,寻找一种在子类中覆盖此设置的方法(我想我需要类似
[JsonStopIgnore]
的东西,但我找不到任何接近的东西)。
JsonSerializer
重新拾取这个属性吗?[JsonIgnore]
,但仅在基类中标记为?
[JsonIgnore]
属性行为的唯一方法是使用合约解析器,正如@Yuval Itzchakov 在他的回答中很好地解释的那样。但是,还有另一种可能适合您的解决方案:您可以在类中实现
[JsonIgnore]
方法来控制
ShouldSerializeParentId()
属性是否被序列化,而不是使用
ParentId
属性。 在基类中,让这个方法返回
false
;然后,重写派生类中的方法以返回
true
。 (此功能在 Json.Net 中称为“条件属性序列化”。)
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您可以通过创建自定义
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>()});
我通过在派生类的属性上使用 new 关键字解决了同样的问题。public class Foo
{
[JsonIgnore]
public int ParentId { get; set; }
}
public class Bar: Foo
{
[JsonProperty("ParentId")]
public new int ParentId { get; set; }
}
您可以简单地在派生类中覆盖
public new int ParentId
{
get { return base.ParentId; }
set { base.ParentId = value; }
}
我用幽灵属性解决了同样的问题:public class Foo
{
[JsonIgnore]
public int ParentId { get; set; }
[NotMapped]
public int FooParent { get; set; }
}
当我想显示这个始终隐藏的属性时,我会填充它,其他时候它为空:
Foos.ForEach(x => x.FooParent = ParentId);
另一种方法是定义一个支持成员变量,然后序列化该支持变量:
public class Foo
{
[JsonIgnore]
public int ParentId { get; set; }
}
public class Bar: Foo
{
[JsonProperty("_parentId")]
private int _parentId;
public int ParentId
{
get
{
return _parentId;
}
set
{
_parentId = value;
}
}
}