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

System.Text.Json是否有类似CustomCreationConverter的实现方案?

System.Text.Json 没有提供和 Newtonsoft.Json CustomCreationConverter<T> 完全同名的开箱即用组件,但完全可以通过自定义 JsonConverter<T> 实现一模一样的能力,你原来写在 Create 方法里的自定义实例化逻辑,基本可以零改动迁移。

通用实现方案

你可以先写一个和 Newtonsoft CustomCreationConverter<T> 签名对齐的泛型基类,后续所有需要自定义创建逻辑的转换器直接继承这个基类、重写Create方法即可,不需要重复写属性映射的逻辑。

兼容 .NET Core 3.0+ 所有版本的基类实现如下:

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

public abstract class CustomCreationConverter<T> : JsonConverter<T> where T : class
{
    // 对齐Newtonsoft的Create方法定义,你的自定义实例化逻辑直接重写这个方法即可
    protected abstract T Create(Type objectType, ref Utf8JsonReader reader, JsonSerializerOptions options);

    public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.StartObject)
        {
            throw new JsonException("当前转换器仅支持对象类型的自定义创建逻辑");
        }

        // 执行你自定义的实例创建逻辑
        T instance = Create(typeToConvert, ref reader, options);

        // 自动将JSON字段填充到已创建的实例上,不需要手动逐属性映射
        using JsonDocument doc = JsonDocument.ParseValue(ref reader);
        var serializeOptions = new JsonSerializerOptions(options);
        // 注入空转换器规避递归调用导致的栈溢出
        serializeOptions.Converters.Add(new EmptyConvertor<T>());
        JsonSerializer.Deserialize(serializeOptions, doc.RootElement, instance);
        return instance;
    }

    public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
    {
        // 写入逻辑复用默认序列化规则即可
        var serializeOptions = new JsonSerializerOptions(options);
        serializeOptions.Converters.Add(new EmptyConvertor<T>());
        JsonSerializer.Serialize(writer, value, typeof(T), serializeOptions);
    }

    // 空转换器用于阻断递归调用
    private class EmptyConvertor<TTarget> : JsonConverter<TTarget> where TTarget : class
    {
        public override TTarget? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => null;
        public override void Write(Utf8JsonWriter writer, TTarget value, JsonSerializerOptions options) {}
    }
}

如果你使用的是 .NET 8 及以上版本,可以用内置的 PopulateObject 方法简化Read逻辑,性能表现更好:

public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
    if (reader.TokenType != JsonTokenType.StartObject)
    {
        throw new JsonException("当前转换器仅支持对象类型的自定义创建逻辑");
    }
    T instance = Create(typeToConvert, ref reader, options);
    // 直接将JSON内容填充到已创建的实例,不需要中转JsonDocument
    JsonSerializer.PopulateObject(ref reader, instance, options);
    return instance;
}
使用示例

用法和你之前用 Newtonsoft 的 CustomCreationConverter 几乎没有区别,比如你需要在创建实例时自动填充默认值、从DI容器取服务、根据JSON字段判断实例类型,直接写在Create方法里即可:

// 示例业务实体
public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime CreateTime { get; set; }
}

// 自定义创建转换器
public class UserCreationConverter : CustomCreationConverter<User>
{
    protected override User Create(Type objectType, ref Utf8JsonReader reader, JsonSerializerOptions options)
    {
        // 这里放你的自定义逻辑,比如:
        // 1. 从服务容器获取已初始化的实例
        // 2. 读取JSON里的type字段判断要创建的子类类型
        // 3. 给不需要从JSON反序列化的字段赋默认值
        return new User
        {
            CreateTime = DateTime.Now
        };
    }
}

// 注册转换器后即可正常使用
var options = new JsonSerializerOptions();
options.Converters.Add(new UserCreationConverter());
// 反序列化时会自动走你定义的Create逻辑
var user = JsonSerializer.Deserialize<User>("{\"Id\":1,\"Name\":\"张三\"}", options);
注意事项
  • 如果你的Create逻辑需要读取JSON中的字段做判断(比如多态反序列化场景),注意读取字段后要将 Utf8JsonReader 的位置复位,避免后续属性填充时丢失字段;更稳妥的方式是先用 JsonDocument 解析出需要判断的字段,再做实例创建。
  • 如果你的创建逻辑不需要读取JSON内容,可以把基类的Create方法签名简化为 protected abstract T Create(Type objectType),和Newtonsoft的签名完全一致,迁移成本为0。

内容的提问来源于stack exchange,提问作者Pop Young

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 06:57:21