You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在System.Text.Json中优先序列化基类属性

如何在System.Text.Json中优先序列化基类属性

嘿,我之前也碰到过这个需求!默认情况下System.Text.Json序列化继承类的时候,会把子类的属性排在前面,基类的属性反而靠后。如果想让基类属性优先输出,有两种实用的方法,我给你详细唠唠:

方法一:用JsonPropertyOrder特性手动指定顺序

这是最直接简单的办法,适合属性不多或者项目规模不大的场景。你只需要给基类的属性设置一个更小的JsonPropertyOrder值,子类的属性设置稍大一点的数值,System.Text.Json就会按照Order从小到大的顺序序列化属性。

比如修改你的类结构:

using System.Text.Json.Serialization;

public class ParentClass {
    [JsonPropertyOrder(-2)]
    public int ParentProperty1 { get; set; }
    [JsonPropertyOrder(-2)]
    public int ParentProperty2 { get; set; }
}

public class ChildClass: ParentClass {
    [JsonPropertyOrder(-1)]
    public int ChildProperty1 { get; set; }
    [JsonPropertyOrder(-1)]
    public int ChildProperty2 { get; set; }
}

public class GrandchildClass: ChildClass {
    [JsonPropertyOrder(0)]
    public int GrandchildProperty1 { get; set; }
    [JsonPropertyOrder(0)]
    public int GrandchildProperty2 { get; set; }
}

这里我给基类属性设为-2,子类-1,孙子类0——数值越小,序列化时越靠前。这样序列化出来的JSON里,Parent的属性就会排在最前面,接着是Child,最后是Grandchild的属性。

方法二:自定义JsonConverter全局控制顺序

如果你的继承类很多,每个属性都加特性太繁琐,那可以写一个自定义的JSON转换器,手动控制序列化时先处理基类属性,再处理子类的。

比如这个通用的转换器:

using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;

public class BaseFirstConverter<T> : JsonConverter<T>
{
    public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 反序列化用默认逻辑就够,我们主要改序列化的顺序
        return JsonSerializer.Deserialize<T>(ref reader, options);
    }

    public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();

        // 先收集从基类到子类的类型链(排除object)
        var typeChain = new List<Type>();
        var currentType = typeof(T);
        while (currentType != null && currentType != typeof(object))
        {
            typeChain.Insert(0, currentType);
            currentType = currentType.BaseType;
        }

        // 遍历类型链,先序列化基类的属性
        foreach (var type in typeChain)
        {
            // 只取当前类型自己声明的公共属性,避免重复序列化继承来的属性
            var properties = type.GetProperties(
                BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);

            foreach (var prop in properties)
            {
                // 处理JsonPropertyName特性,确保别名生效
                var propName = prop.GetCustomAttribute<JsonPropertyNameAttribute>()?.Name ?? prop.Name;
                var propValue = prop.GetValue(value);

                // 用默认序列化逻辑写入属性
                JsonSerializer.Serialize(
                    writer,
                    propName: propName,
                    value: propValue,
                    inputType: prop.PropertyType,
                    options: options);
            }
        }

        writer.WriteEndObject();
    }
}

使用的时候,只需要在JsonSerializerOptions里添加这个转换器就行:

var grandchild = new GrandchildClass
{
    ParentProperty1 = 1,
    ParentProperty2 = 2,
    ChildProperty1 = 3,
    ChildProperty2 = 4,
    GrandchildProperty1 = 5,
    GrandchildProperty2 = 6
};

var options = new JsonSerializerOptions();
options.Converters.Add(new BaseFirstConverter<GrandchildClass>());

var json = JsonSerializer.Serialize(grandchild, options);

这个转换器会自动先处理最上层的基类属性,再依次处理子类的,完全不用给每个属性加特性,适合大型项目或者有很多继承类的场景。

小提醒

如果你的属性还加了其他System.Text.Json的特性(比如JsonIgnore),自定义转换器里的默认序列化逻辑会自动识别,不用额外处理,这点很省心。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 12:39:40