实现抽象基础字段时在序列化期间继承属性

问题描述

我有一个抽象类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 docsJsonIgnoreAttribute docs都没有讨论[JsonIgnore]是否被继承,但是.Net 3.1 source code for JsonIgnoreAttributecurrent 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.JsonIgnoreAttributeIgnoreDataMemberAttribute的继承,如演示小提琴#2 here中所示。您可能想open an issue对此进行讨论;至少应澄清文档。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...