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

System.Text.Json反序列化构造函数参数绑定异常的解决方法

问题描述

我定义了如下C#类:

public class BaseResponse
{
    public bool Success { get; set; }

    public string Message { get; set; }

    public BaseResponse(bool success, string message)
    {
        Success = success;
        Message = message;
    }
}

public class TextToSpeechResponse : BaseResponse
{
    [JsonPropertyName("audioPreviewSuccess")]
    public bool AudioPreviewSuccess { get; set; }

    [JsonPropertyName("result")]
    public SpeechSynthesisResult? Result { get; set; }

    [JsonPropertyName("errorMessage")]
    public string? ErrorMessage { get; set; }

    [JsonConstructor]
    public TextToSpeechResponse(bool audioPreviewSuccess, SpeechSynthesisResult speechResult, string? errorMessage, string message)
        : base(true, message)
    {
        AudioPreviewSuccess = audioPreviewSuccess;
        Result = speechResult;
        ErrorMessage = errorMessage;
    }

    public TextToSpeechResponse()
        : base(false, string.Empty)
    {
        AudioPreviewSuccess = false;
        Result              = null;
        ErrorMessage        = string.Empty;
    }
}

尝试使用以下代码反序列化JSON:

var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
};

return JsonSerializer.Deserialize<TextToSpeechResponse>(authorizedResponseBody, options) ??
       new TextToSpeechResponse {
           Message = "Something went wrong with deserializing the authorizedResponseBody.",
       };

但抛出如下异常:

Each parameter in the deserialization constructor on type 'CpatCognitiveServicesApp.Responses.TextToSpeechResponse' must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. Fields are only considered when 'JsonSerializerOptions.IncludeFields' is enabled. The match can be case-insensitive.

对应的JSON字符串:

{
    "audioPreviewSuccess": true,
    "result": {
        "resultId": "ee80d3cf5f154fbba69401a4254b5b26",
        "reason": 9,
        "audioData": "UklGRnb1AABXQVZFZm10IBIAAAABAAEAgD4AAAB9AAACABAAAABkYXRhUPUAAAA",
        "properties": {}
    },
    "errorMessage": null
}

我曾误以为问题源于JSON中的properties字段为空对象{},尝试添加UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode以及自定义类替换SpeechSynthesisResult,但异常仍未解决,请问如何成功反序列化?

问题分析

异常的核心原因是标记了[JsonConstructor]的构造函数参数绑定失败,和properties空对象无关:

  1. 构造函数中的speechResult参数,与类中属性Result名称不匹配——System.Text.Json要求反序列化构造函数的参数名必须和类的属性/字段名一致(大小写不敏感),这里参数名speechResult和属性名Result不对应,无法绑定。
  2. 构造函数要求message参数,但传入的JSON中没有对应的message字段,没有可绑定的数据源。
解决方案

方案一:修正JsonConstructor构造函数的参数

调整构造函数的参数名,使其与属性名匹配,并给message设置默认值(适配JSON中无该字段的情况):

[JsonConstructor]
public TextToSpeechResponse(bool audioPreviewSuccess, SpeechSynthesisResult? result, string? errorMessage, string message = "")
    : base(true, message)
{
    AudioPreviewSuccess = audioPreviewSuccess;
    Result = result;
    ErrorMessage = errorMessage;
}
  • 将speechResult改为result,与属性Result名称一致,满足参数-属性绑定要求
  • 给message设置默认值"",确保JSON中无该字段时也能正常实例化

方案二:移除JsonConstructor特性

直接去掉[JsonConstructor],让System.Text.Json使用无参构造函数实例化对象,再自动赋值属性:

// 移除[JsonConstructor]特性
public TextToSpeechResponse(bool audioPreviewSuccess, SpeechSynthesisResult speechResult, string? errorMessage, string message)
    : base(true, message)
{
    AudioPreviewSuccess = audioPreviewSuccess;
    Result = speechResult;
    ErrorMessage = errorMessage;
}

这样反序列化流程会改为:调用无参构造函数创建对象 → 逐个匹配JSON字段赋值属性,避开构造函数参数绑定的问题。

额外处理:SpeechSynthesisResult的properties字段

如果SpeechSynthesisResult是第三方类,空对象{}仍导致问题,可通过以下方式处理:

  1. 修改序列化配置:
var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode // 处理未知类型的空对象
};
  1. 自定义替代类:
public class CustomSpeechSynthesisResult
{
    public string ResultId { get; set; }
    public int Reason { get; set; }
    public string AudioData { get; set; }
    public Dictionary<string, object> Properties { get; set; } = new();
}

然后将TextToSpeechResponse中的SpeechSynthesisResult? Result改为CustomSpeechSynthesisResult? Result。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 23:42:31