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

如何在自定义JSON转换器中访问.NET类的自定义属性

在自定义JSON转换器中访问.NET类的自定义属性

要在你的StringSanitizingConverter中读取目标属性的自定义属性,我们可以分三步实现,同时兼顾灵活性和通用性:


1. 定义自定义标记属性

先创建一个可配置的自定义属性,用来标记需要特殊处理的字符串属性,还能通过参数控制修剪逻辑:

[AttributeUsage(AttributeTargets.Property)]
public class StringSanitizeSettingsAttribute : Attribute
{
    // 默认修剪首尾空格
    public bool TrimLeading { get; set; } = true;
    public bool TrimTrailing { get; set; } = true;
    // 可选:合并中间多余空格
    public bool CollapseExtraSpaces { get; set; } = false;
}

2. 修改自定义转换器,添加属性读取逻辑

核心思路是:在反序列化时定位当前处理的属性,通过反射获取它的自定义属性,再根据配置处理字符串。下面的实现同时支持根对象和嵌套对象场景:

public class StringSanitizingConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(string);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;

        string rawValue = reader.Value.ToString();
        if (string.IsNullOrWhiteSpace(rawValue))
            return rawValue;

        // 1. 获取当前属性的路径(如 "CandidateName" 或 "Address.Street")
        string propertyPath = reader.Path;
        string targetPropName = propertyPath.Split('.').Last();

        // 2. 定位属性所属的父对象类型
        Type parentType = GetParentObjectType(reader, serializer);
        if (parentType == null)
            return rawValue.Trim(); // 无上下文时默认修剪首尾

        // 3. 通过反射读取自定义属性配置
        PropertyInfo targetProp = parentType.GetProperty(targetPropName);
        var sanitizeConfig = targetProp?.GetCustomAttribute<StringSanitizeSettingsAttribute>();

        // 4. 根据配置处理字符串
        if (sanitizeConfig != null)
        {
            if (sanitizeConfig.TrimLeading)
                rawValue = rawValue.TrimStart();
            if (sanitizeConfig.TrimTrailing)
                rawValue = rawValue.TrimEnd();
            if (sanitizeConfig.CollapseExtraSpaces)
                rawValue = System.Text.RegularExpressions.Regex.Replace(rawValue, @"\s+", " ");
        }
        else
        {
            // 未标记自定义属性时的默认行为
            rawValue = rawValue.Trim();
        }

        return rawValue;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue(value?.ToString());
    }

    // 辅助方法:获取当前属性所属的父对象类型
    private Type GetParentObjectType(JsonReader reader, JsonSerializer serializer)
    {
        // 处理根对象场景:从序列化上下文获取类型
        if (reader.Parent == null)
            return serializer.Context.Context as Type;

        // 处理嵌套对象场景:回溯JToken获取父对象类型
        JToken currentToken = reader.CurrentToken;
        while (currentToken.Parent != null)
        {
            currentToken = currentToken.Parent;
            if (currentToken is JObject parentObj)
            {
                var objContract = serializer.ContractResolver.ResolveContract(parentObj.GetType()) as JsonObjectContract;
                return objContract?.UnderlyingType;
            }
        }

        return null;
    }
}

3. 在实体类中使用自定义属性和转换器

现在可以在你的Candidate类中标记属性,指定不同的处理规则:

public class Candidate 
{ 
    // 标记需要合并多余空格的属性
    [StringSanitizeSettings(CollapseExtraSpaces = true)]
    [JsonConverter(typeof(StringSanitizingConverter))]
    public string CandidateName { get; set; } 

    // 使用默认配置(仅修剪首尾空格)
    [StringSanitizeSettings]
    [JsonConverter(typeof(StringSanitizingConverter))]
    public string Email { get; set; }
}

反序列化配置示例

如果全局注册转换器(而非在每个属性上标记[JsonConverter]),记得传递根对象类型上下文,确保转换器能正确识别嵌套属性:

var jsonSettings = new JsonSerializerSettings
{
    Converters = new List<JsonConverter> { new StringSanitizingConverter() },
    // 传递根对象类型,帮助转换器定位属性所属类
    Context = new StreamingContext(StreamingContextStates.All, typeof(Candidate))
};

// 测试反序列化
string json = "{\"CandidateName\": \"  John  Doe  \", \"Email\": \"  john@example.com  \"}";
var candidate = JsonConvert.DeserializeObject<Candidate>(json, jsonSettings);
// 结果:CandidateName = "John Doe",Email = "john@example.com"

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:23:22