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

如何构建C#类以反序列化含多类型属性的JSON数据

如何让C#类的属性同时支持字符串和整数类型的JSON反序列化?

当然可以!要处理这种JSON中同一字段既可能是字符串又可能是整数的情况,最可靠的方式是通过自定义JSON转换器来实现,或者用私有中间属性做过渡处理。下面我给你两种主流JSON库的解决方案,以及一个简化的替代方案:

方法1:使用Newtonsoft.Json(Json.NET)的自定义转换器

这是.NET生态里最常用的JSON库,自定义转换器可以完美处理类型兼容问题。

首先创建一个转换器,用来把月份名称(比如"may")和数字(比如5)统一转换成整数类型:

public class MonthConverter : JsonConverter<int>
{
    // 存储月份名称到数字的映射,忽略大小写
    private static readonly Dictionary<string, int> _monthNames = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
    {
        ["january"] = 1, ["february"] = 2, ["march"] = 3, ["april"] = 4,
        ["may"] = 5, ["june"] = 6, ["july"] = 7, ["august"] = 8,
        ["september"] = 9, ["october"] = 10, ["november"] = 11, ["december"] = 12
    };

    public override int ReadJson(JsonReader reader, Type objectType, int existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        // 处理字符串类型的月份
        if (reader.TokenType == JsonToken.String)
        {
            var monthStr = reader.Value.ToString();
            if (_monthNames.TryGetValue(monthStr, out int month))
                return month;
            
            throw new JsonSerializationException($"无效的月份名称:{monthStr}");
        }
        // 处理整数类型的月份
        else if (reader.TokenType == JsonToken.Integer)
        {
            var monthNum = Convert.ToInt32(reader.Value);
            if (monthNum is >=1 and <=12)
                return monthNum;
            
            throw new JsonSerializationException($"无效的月份数字:{monthNum}");
        }

        throw new JsonSerializationException($"不支持的Token类型:{reader.TokenType}");
    }

    public override void WriteJson(JsonWriter writer, int value, JsonSerializer serializer)
    {
        // 序列化时可以选择输出数字或者名称,这里默认输出数字
        writer.WriteValue(value);
        // 如果要输出月份名称,替换成下面这行:
        // writer.WriteValue(_monthNames.First(kv => kv.Value == value).Key);
    }
}

然后定义你的SomeObject类,给BirthMonth属性加上转换器特性:

public class SomeObject
{
    public string Name { get; set; }

    [JsonConverter(typeof(MonthConverter))]
    public int BirthMonth { get; set; }
}

别忘了定义包裹它的外层类(因为你的JSON是嵌套结构):

public class Wrapper
{
    public SomeObject SomeObject { get; set; }
}

现在测试反序列化两种格式的JSON:

// 格式1:字符串月份
var json1 = "{ \"SomeObject\" : { \"name\" : \"something\", \"birthMonth\" : \"may\" } }";
var result1 = JsonConvert.DeserializeObject<Wrapper>(json1);

// 格式2:整数月份
var json2 = "{ \"SomeObject\" : { \"name\" : \"something\", \"birthMonth\" : 5 } }";
var result2 = JsonConvert.DeserializeObject<Wrapper>(json2);

方法2:使用System.Text.Json(.NET Core/.NET 5+内置)的自定义转换器

如果你用的是.NET Core或更高版本的内置JSON库,同样可以自定义转换器:

public class MonthConverter : JsonConverter<int>
{
    private static readonly Dictionary<string, int> _monthNames = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
    {
        ["january"] = 1, ["february"] = 2, ["march"] = 3, ["april"] = 4,
        ["may"] = 5, ["june"] = 6, ["july"] = 7, ["august"] = 8,
        ["september"] = 9, ["october"] = 10, ["november"] = 11, ["december"] = 12
    };

    public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.String)
        {
            var monthStr = reader.GetString();
            if (_monthNames.TryGetValue(monthStr, out int month))
                return month;
            
            throw new JsonException($"无效的月份名称:{monthStr}");
        }
        else if (reader.TokenType == JsonTokenType.Number)
        {
            if (reader.TryGetInt32(out int monthNum) && monthNum is >=1 and <=12)
                return monthNum;
            
            throw new JsonException($"无效的月份数字:{reader.GetInt32()}");
        }

        throw new JsonException($"不支持的Token类型:{reader.TokenType}");
    }

    public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
    {
        writer.WriteNumberValue(value);
        // 要输出月份名称的话,替换成:
        // writer.WriteStringValue(_monthNames.First(kv => kv.Value == value).Key);
    }
}

然后修改SomeObject类的特性(注意是System.Text.Json的特性):

using System.Text.Json.Serialization;

public class SomeObject
{
    public string Name { get; set; }

    [JsonConverter(typeof(MonthConverter))]
    public int BirthMonth { get; set; }
}

同样需要外层Wrapper类,测试代码:

var json1 = "{ \"SomeObject\" : { \"name\" : \"something\", \"birthMonth\" : \"may\" } }";
var result1 = JsonSerializer.Deserialize<Wrapper>(json1);

var json2 = "{ \"SomeObject\" : { \"name\" : \"something\", \"birthMonth\" : 5 } }";
var result2 = JsonSerializer.Deserialize<Wrapper>(json2);

替代方案:用私有中间属性处理(无需自定义转换器)

如果不想写单独的转换器,也可以用一个私有属性来接收原始值,再转换到BirthMonth:

using System.Globalization;
using Newtonsoft.Json; // 或者用System.Text.Json的[JsonPropertyName]

public class SomeObject
{
    public string Name { get; set; }

    public int BirthMonth { get; set; }

    // 用这个私有属性接收JSON里的原始值
    [JsonProperty("birthMonth")] // 如果用System.Text.Json,换成[JsonPropertyName("birthMonth")]
    private object BirthMonthRaw
    {
        set
        {
            switch (value)
            {
                case int num:
                    if (num is >=1 and <=12)
                        BirthMonth = num;
                    else
                        throw new ArgumentException($"无效的月份数字:{num}");
                    break;
                case string str:
                    // 用DateTime内置方法解析月份名称
                    if (DateTime.TryParseExact(str, "MMMM", CultureInfo.InvariantCulture, DateTimeStyles.None, out var date))
                        BirthMonth = date.Month;
                    else
                        throw new ArgumentException($"无效的月份名称:{str}");
                    break;
                default:
                    throw new ArgumentException($"不支持的birthMonth类型:{value.GetType()}");
            }
        }
    }
}

这种方式更轻量,适合简单场景,但只处理反序列化逻辑,序列化还是用BirthMonth的整数输出。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:56:23