问题描述
我有一个抽象类Base
,它希望每个派生类都实现一个属性SortValue
。此属性应具有适用于所有派生实例的属性,在本例中为JsonIgnore
。
正在发生的事情似乎是Derived
不尊重该属性。至少,在由System.Text.Json进行序列化时,不会忽略该属性。
如何在确保每个子类都实现SortValue
的同时实现属性继承?
public abstract class Base
{
[JsonIgnore]
public abstract IComparable SortValue { get; }
}
public class Derived : Base
{
public int VoteCount { get; set; }
// Desire: inherited JsonIgnore attribute
public override IComparable SortValue => VoteCount;
}
解决方法
更新:这是System.Text.Json
的预期行为:
在comments Noah Stahl中链接到this issue
System.Text.Json.JsonSerializer.Serialize ignores JsonPropertyName on abstract properties #3979
这是已知的/设计使然。属性不能继承System.Text.Json属性。该属性需要放置在每个(可反序列化的)替代上。
一种解决方法,您可以将SortValue
设为公开的,非虚拟的代理,从而调用某些受保护的抽象属性,如下所示:
public abstract class Base
{
protected abstract IComparable ProtectedSortValue { get; }
[JsonIgnore]
public IComparable SortValue => ProtectedSortValue;
}
public class Derived : Base
{
public int VoteCount { get; set; }
protected override IComparable ProtectedSortValue => VoteCount;
}
进行此更改后,SortValue
将不会在派生类中进行序列化,而ProtectedSortValue
则将不会进行序列化,因为仅序列化了公共属性。演示小提琴#3 here。
(将[JsonIgnore]
添加到重写的属性还会阻止其序列化,但是有必要在每个派生类中执行此操作,而这似乎是您不想执行的。)
原始答案:这可能是对System.Text.Json
的限制。我能够使用以下代码重现您的问题:
var derived = new Derived { VoteCount = 101 };
var json1 = JsonSerializer.Serialize(derived,typeof(Derived));
Console.WriteLine(json1); // {"VoteCount":101,"SortValue":{}}
var json2 = JsonSerializer.Serialize(derived,typeof(Base));
Console.WriteLine(json2); //{}
将Derived
的实例序列化为类型Derived
时,将包含SortValue
属性;但是当序列化为类型Base
时不是。演示小提琴#1 here。
但是这种行为是故意的吗? overview docs和JsonIgnoreAttribute
docs都没有讨论[JsonIgnore]
是否被继承,但是.Net 3.1 source code for JsonIgnoreAttribute
和current source都显示[AttributeUsage(AttributeTargets.Property,AllowMultiple = false)]
:
[AttributeUsage(AttributeTargets.Property,AllowMultiple = false)]
public sealed class JsonIgnoreAttribute : JsonAttribute
{
/// <summary>
/// Initializes a new instance of <see cref="JsonIgnoreAttribute"/>.
/// </summary>
public JsonIgnoreAttribute() { }
}
请注意,未设置AttributeUsageAttribute.Inherited
。由于Inherited
的默认值为documented,如下所示:
true
,如果属性可以被派生类和重写成员继承;否则为false
。 默认值为true
。
似乎[JsonIgnore]
应该已被重写属性继承。它肯定与Json.NET和DataContractJsonSerializer
不一致,它们分别支持Newtonsoft.Json.JsonIgnoreAttribute
和IgnoreDataMemberAttribute
的继承,如演示小提琴#2 here中所示。您可能想open an issue对此进行讨论;至少应澄清文档。