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

C#使用Newtonsoft反序列化类型不匹配未抛预期异常如何优雅处理

核心原因

Newtonsoft.Json 默认反序列化行为是:当 JSON 字段值类型与实体类属性类型不匹配时,会静默将属性赋值为null,不会主动抛出异常,因此只有访问属性成员时才会触发空引用异常。


可选解决方案

方案1:反序列化阶段启用严格校验(推荐用于严格校验场景)

直接配置反序列化参数,在类型不匹配时直接抛出异常,将错误提前到反序列化阶段处理:

var deserializeSettings = new JsonSerializerSettings
{
    Error = (sender, args) =>
    {
        if (args.ErrorContext.Error is JsonSerializationException)
        {
            // 可自定义错误信息,明确告知哪个字段格式错误
            throw new InvalidOperationException($"字段[{args.ErrorContext.Member}]格式不合法:{args.ErrorContext.Error.Message}", args.ErrorContext.Error);
        }
        args.ErrorContext.Handled = false;
    },
    // 可选配置:遇到JSON中存在实体类没有的字段时也抛出异常
    MissingMemberHandling = MissingMemberHandling.Error
};

using (StreamReader r = new StreamReader(filePath))
{
    string json = r.ReadToEnd();
    // 反序列化时传入配置
    EmailStructureRequestModel emailStructure = JsonConvert.DeserializeObject<EmailStructureRequestModel>(json, deserializeSettings);
    // ...后续逻辑
}

配置后当Cc/Bcc传空字符串时,反序列化阶段就会直接抛出格式错误,不用等到访问属性时才处理。


方案2:自定义类型转换器(推荐用于兼容空字符串场景)

如果希望空字符串自动转为空列表而不是抛异常,可以自定义转换器适配不规范的输入:

  1. 先定义转换器
public class StringToListConverter : JsonConverter<List<string>>
{
    public override List<string> ReadJson(JsonReader reader, Type objectType, List<string> existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        // 如果输入是字符串类型
        if (reader.TokenType == JsonToken.String)
        {
            string strValue = reader.Value?.ToString();
            // 空字符串返回空列表,如果希望非空字符串也报错可以在这里加抛出逻辑
            return string.IsNullOrWhiteSpace(strValue) ? new List<string>() : throw new JsonSerializationException("预期为数组类型,实际为非空字符串");
        }
        // 正常数组走默认转换逻辑
        return serializer.Deserialize<List<string>>(reader);
    }

    public override void WriteJson(JsonWriter writer, List<string> value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}
  1. 在实体类属性上挂载转换器
[JsonProperty(PropertyName = "Cc")]
[JsonConverter(typeof(StringToListConverter))]
public List<string> Cc { get; set; }

[JsonProperty(PropertyName = "Bcc")]
[JsonConverter(typeof(StringToListConverter))]
public List<string> Bcc { get; set; }

配置后空字符串会自动转为空列表,访问Cc.Count不会再触发空引用异常。


方案3:实体类兜底初始化(最简单的兜底方案)

在实体类中初始化集合,属性赋值时自动兜底为空列表,从根源避免空引用:

public class EmailStructureRequestModel
{
    public EmailStructureRequestModel()
    {
        // 构造时初始化所有集合属性
        To = new List<string>();
        Cc = new List<string>();
        Bcc = new List<string>();
    }

    [JsonProperty(PropertyName = "Sender", Required = Required.Always)]
    public EmailSender Sender { get; set; }
    
    [JsonProperty(PropertyName = "to", Required = Required.Always)]
    public List<string> To { get; set; }
    
    private List<string> _cc;
    [JsonProperty(PropertyName = "Cc")]
    public List<string> Cc 
    { 
        get => _cc;
        // 赋值为null时自动兜底为空列表
        set => _cc = value ?? new List<string>();
    }
    
    private List<string> _bcc;
    [JsonProperty(PropertyName = "Bcc")]
    public List<string> Bcc 
    { 
        get => _bcc;
        set => _bcc = value ?? new List<string>();
    }
    
    [JsonProperty(PropertyName = "Content", Required = Required.Always)]
    public EmailContent Content { get; set; }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 20:27:03