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

.NET Core中降低JsonPatchDocument验证代码认知复杂度的方案

.NET Core中降低JsonPatchDocument验证代码认知复杂度的方案

在.NET Core开发中,需在将请求中的JsonPatchDocument应用到对象前验证其操作:如replace操作的path/value为空时需返回400 Bad Request,copy、move等操作也需对应校验。最初使用switch-case写法,后改为if-else,但两种实现的认知复杂度均超过CodeClimate设定的20阈值(当前为28),导致CI流水线失败。

原switch-case实现

foreach (var operation in patchDocument.Operations)
{
    var op = operation.op;
    var path = operation.path;
    var value = operation.value;
    var from = operation.from;
    switch (op)
    {
        case "add":
        case "replace":
        case "test":
            if (string.IsNullOrEmpty(path) || value == null)
            {
                return this.BadRequest(this.ModelState);
            }
            break;
        case "copy":
        case "move":
            if (string.IsNullOrEmpty(path) || string.IsNullOrEmpty(from))
            {
                return this.BadRequest(this.ModelState);
            }
            break;
        case "remove":
            if (string.IsNullOrEmpty(path))
            {
                return this.BadRequest(this.ModelState);
            }
            break;
        default:
            return this.BadRequest(this.ModelState);
    }
}

修改后的if-else实现

private static bool ValidatePatchRequest(JsonPatchDocument<UserPatch> patchDocument)
{
    var validationResult = false;

    foreach (var item in patchDocument.Operations)
    {
        if (string.IsNullOrEmpty(item.op))
        {
            validationResult = false;
            break;
        }

        if (item.op == "add" || item.op == "test" || item.op == "replace")
        {
            if (string.IsNullOrEmpty(item.path) || item.value == null)
            {
                validationResult = false;
                break;
            }
        }

        if (item.op == "copy" || item.op == "move")
        {
            if (string.IsNullOrEmpty(item.path) || item.from == null)
            {
                validationResult = false;
                break;
            }
        }

        if (item.op == "remove")
        {
            if (string.IsNullOrEmpty(item.path))
            {
                validationResult = false;
                break;
            }
        }

        validationResult = true;
    }

    return validationResult;
}

CodeClimate错误提示

[{"engine_name":"structure","fingerprint":"7558ff4c7ee81fda7b1f****","categories":["Complexity"],"check_name":"method_complexity","content":{"body":"# 认知复杂度\n认知复杂度用于衡量一段代码的直观理解难度。与圈复杂度(衡量代码测试难度)不同,认知复杂度告诉你代码的阅读和理解难度。\n\n### 方法的认知复杂度基于以下简单规则:\n* 使用语言提供的简写将多个语句合并为一个时,代码不会被认为更复杂\n* 每出现一次“代码线性流程中断”,代码复杂度会增加\n* 当“流程中断结构嵌套”时,代码复杂度会增加\n\n### 扩展阅读\n* 认知复杂度文档\n* 认知复杂度:衡量代码易懂性的新方式\n"},"description":"方法ValidatePatchRequest的认知复杂度为28(超过允许的20)。考虑重构。","location":{"path":"****Controller.cs","lines":{"begin":233,"end":276}},"other_locations":[],"remediation_points":950000,"severity":"minor","type":"issue"},
{"name":"csharp.parse.succeeded","type":"measurement","value":15,"engine_name":"structure"},
{"name":"csharp.parse.succeeded","type":"measurement","value":15,"engine_name":"duplication"}]

降低认知复杂度的验证方案

方案一:字典映射操作与验证逻辑

将每种操作对应的验证逻辑封装为委托,通过字典建立映射,主方法保持线性流程,无嵌套判断:

private delegate bool PatchOperationValidator(JsonPatchOperation operation);

private static readonly Dictionary<string, PatchOperationValidator> _operationValidators = new Dictionary<string, PatchOperationValidator>
{
    ["add"] = op => !string.IsNullOrEmpty(op.path) && op.value != null,
    ["replace"] = op => !string.IsNullOrEmpty(op.path) && op.value != null,
    ["test"] = op => !string.IsNullOrEmpty(op.path) && op.value != null,
    ["copy"] = op => !string.IsNullOrEmpty(op.path) && !string.IsNullOrEmpty(op.from),
    ["move"] = op => !string.IsNullOrEmpty(op.path) && !string.IsNullOrEmpty(op.from),
    ["remove"] = op => !string.IsNullOrEmpty(op.path)
};

private static bool ValidatePatchRequest(JsonPatchDocument<UserPatch> patchDocument)
{
    if (patchDocument?.Operations == null)
        return false;

    foreach (var operation in patchDocument.Operations)
    {
        if (string.IsNullOrEmpty(operation.op))
            return false;

        if (!_operationValidators.TryGetValue(operation.op, out var validator))
            return false;

        if (!validator(operation))
            return false;
    }

    return true;
}

方案二:提取验证方法+模式匹配

将不同操作组的验证逻辑拆分为独立方法,主方法使用C# 8.0+的模式匹配switch表达式,简化流程:

private static bool ValidatePatchRequest(JsonPatchDocument<UserPatch> patchDocument)
{
    if (patchDocument?.Operations == null)
        return false;

    foreach (var operation in patchDocument.Operations)
    {
        if (string.IsNullOrEmpty(operation.op))
            return false;

        var isValid = operation.op switch
        {
            "add" or "replace" or "test" => ValidateAddReplaceTest(operation),
            "copy" or "move" => ValidateCopyMove(operation),
            "remove" => ValidateRemove(operation),
            _ => false
        };

        if (!isValid)
            return false;
    }

    return true;
}

private static bool ValidateAddReplaceTest(JsonPatchOperation operation)
{
    return !string.IsNullOrEmpty(operation.path) && operation.value != null;
}

private static bool ValidateCopyMove(JsonPatchOperation operation)
{
    return !string.IsNullOrEmpty(operation.path) && !string.IsNullOrEmpty(operation.from);
}

private static bool ValidateRemove(JsonPatchOperation operation)
{
    return !string.IsNullOrEmpty(operation.path);
}

这两种方案都能大幅降低认知复杂度,符合CodeClimate的阈值要求,同时保持代码的可读性与可维护性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 16:37:55