我不想用这个转换器来装饰我的财产

[JsonConverter(typeof(CustomJsonConverter))]
public string xyz {get;set;}

我需要这样使用它

JsonSerializerOptions _options = new()
{
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    PropertyNameCaseInsensitive = true,
    Converters = { new CustomJsonConverter() }
};

var result = JsonSerializer.DeserializeAsync<T>(stream, _options);

public class CustomJsonConverter : JsonConverter<string>
{
    public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
         if (reader.TokenType == JsonTokenType.PropertyName)
         {
             var propertyName = reader.GetString();

             if (propertyName == "xyz")
             {
                  reader.Read(); // Move to the property value
                  string originalValue = reader.GetString();

                  // Modify the string value (e.g., add a prefix)
                 string modifiedValue = "Modified: " + originalValue;

                 return modifiedValue;
            }
        }

        return reader.GetString();
    }

    public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
    {
        // Write the value as a string
        writer.WriteStringValue(value);
    }
}

reader.TokenType始终等于JsonTokenType. String,因此它永远不会出现在if语句中

if (reader.TokenType == JsonTokenType.PropertyName)

推荐答案

.NET 8.NET 9 Preview 2开始,无法获得父属性名或JsonConverter<T>.Read()内部的序列化路径的任何其他部分,因为它不为Utf8JsonReader所知. 如需确认,请参见this answer105. 正如您所看到的,当调用Read()时,读取器已经前进到属性名之外.

相反,在.NET 7 and later中,您可以使用typeInfo modifier以编程方式将转换器应用于名为xyz的任何属性.要执行此操作,请首先创建以下修改器和转换器:

public static partial class JsonExtensions
{
    public static Action<JsonTypeInfo> AddPropertyConverter(JsonConverter converter, string name) => typeInfo =>
    {
        // Use StringComparison.OrdinalIgnoreCase if you want to apply the comparer to properties named Xyz and XYZ also.
        foreach (var property in typeInfo.Properties.Where(p => converter.CanConvert(p.PropertyType)
                                                           && String.Equals(p.GetMemberName(), name, StringComparison.Ordinal)))
        {
            // If you only want to apply the converter only when there is not one already, use ??=
            // property.CustomConverter ??= CustomJsonConverter.Instance;
            property.CustomConverter = CustomJsonConverter.Instance;
        }
    };

    public static string? GetMemberName(this JsonPropertyInfo property) => (property.AttributeProvider as MemberInfo)?.Name;
}

public class CustomJsonConverter : JsonConverter<string?>
{
    public static CustomJsonConverter Instance { get; } = new(); // Cache a single instance for performance

    public override bool HandleNull => false; // Change to true if you want to modify null string values.

    public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
        "Modified: " + reader.GetString();

    public override void Write(Utf8JsonWriter writer, string? value, JsonSerializerOptions options) => 
        // Write the value as a string
        writer.WriteStringValue(value);
}

然后在. NET 8和更高版本中,使用WithAddedModifier()将修饰符应用到您想要的IJsonTypeInfoResolver:

string propertyName = "xyz";

JsonSerializerOptions _options = new()
{
    // Configure either a DefaultJsonTypeInfoResolver or some JsonSerializerContext and add the required modifier:
    TypeInfoResolver = new DefaultJsonTypeInfoResolver()
        .WithAddedModifier(JsonExtensions.AddPropertyConverter(CustomJsonConverter.Instance, propertyName)),
    // Add other options as required
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    PropertyNameCaseInsensitive = true,             
};

或者在. NET 7中直接创建并配置DefaultJsonTypeInfoResolver,如下所示:

string propertyName = "xyz";

JsonSerializerOptions _options = new()
{
    TypeInfoResolver = new DefaultJsonTypeInfoResolver()
    {
        Modifiers = {JsonExtensions.AddPropertyConverter(CustomJsonConverter.Instance, propertyName)}
    },
    // Add other options as required
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    PropertyNameCaseInsensitive = true,             
};

现在,在反序列化过程中,您的转换器将根据需要重新映射类型为string的所有名为xyz的属性的值,而无需向序列化类添加属性或以其他方式修改这些属性.

请注意,如果希望重映射值为null的属性,则必须重写HandleNull并返回true.

.NET8here和.NET7here的演示小提琴.

Csharp相关问答推荐

Autofac:如何防止丢弃通过ServicCollection注册的服务?

如何使用FastEndpoints和.NET 8 WebAppliationBuilder进行集成测试?

如何在C#中将对象[*,*]直接转换为字符串[*,*]?

Polly使用泛型重试和重试包装函数

如何使用C#Interop EXCEL创建度量衡

在不添加不必要的尾随零的情况下本地化浮点型?

从另一个不同 struct 的数组创建Newtonsoft.Json.Linq.J数组

带有可选参数的模拟方法返回意外的不同值,具体取决于可选的默认值

在Docker容器中运行API项目时,无法本地浏览到index.html

Blazor Fluent UI DialogService,<;FluentDialogProvider/>;错误

如何在microsoft.clearscript.v8的jsondata中使用Linq

如何使用Npgsql从SELECT获得所有查询结果

Blazor服务器项目中的Blazor/.NET 8/Web API不工作

如何对特定异常使用Polly重试机制?

正在try 将自定义字体添加到我的控制台应用程序

在ObservableCollection上使用[NotifyPropertyChangedFor()]源代码生成器不会更新UI

并发表更新.EF核心交易

仅在Blazor Web App中覆盖生产的基本路径(.NET8中的_Hosts.cshtml文件功能?)

SharpZipLib在文件名前加上目录名,生成tar.gz

使用SQL Server 2022+时,我是否必须将代码从SqlConnection类对象中迁移出来?