You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C#代码重构:将内部foreach循环权限校验移至外部循环

重构嵌套循环,减少数据库权限校验调用次数

嘿,这个优化方向太对了——数据库调用的IO开销本来就大,内层循环反复调用完全是浪费资源。咱们只需要把权限校验提前到外层,每个Request只做一次校验,就能把性能提上去。

先看看你原来的代码大概是这样的(还原嵌套循环的问题场景):

foreach (var request in requestsList)
{
    foreach (var item in request.anotherList)
    {
        // 每次内层循环都触发数据库调用,成本极高
        if (myVar.hasPermissions(request)) 
        {
            DoSomething(item);
        }
    }
}

下面给你几种重构方案,按需选择:

方案1:先筛选有权限的Request,再处理内层集合

这种方式最直接,先把所有有权限的Request挑出来,再遍历它们的内层列表,完全避免重复校验:

// 第一步:外层循环一次性校验每个Request的权限
var authorizedRequests = new List<Request>();
foreach (var request in requestsList)
{
    // 每个Request仅调用一次数据库
    if (myVar.hasPermissions(request))
    {
        authorizedRequests.Add(request);
    }
}

// 第二步:只处理有权限的Request的内层数据
foreach (var request in authorizedRequests)
{
    foreach (var item in request.anotherList)
    {
        DoSomething(item);
    }
}

如果习惯用LINQ,也可以简化成一行筛选(同步场景下):

var authorizedRequests = requestsList.Where(r => myVar.hasPermissions(r)).ToList();

foreach (var request in authorizedRequests)
{
    foreach (var item in request.anotherList)
    {
        DoSomething(item);
    }
}

方案2:缓存权限结果(需要保留无权限Request的处理逻辑)

如果你的业务需要对无权限的Request做额外处理(比如打日志、返回提示),可以先把每个Request的权限结果缓存到字典里,后续直接读取缓存:

// 先缓存所有Request的权限结果,仅一次数据库调用/每个Request
var permissionCache = new Dictionary<int, bool>(); // 用Request的Id当键更稳妥,避免对象哈希问题
foreach (var request in requestsList)
{
    permissionCache[request.Id] = myVar.hasPermissions(request);
}

// 遍历处理所有Request,直接用缓存的权限结果
foreach (var request in requestsList)
{
    if (permissionCache.TryGetValue(request.Id, out bool hasPermission) && hasPermission)
    {
        foreach (var item in request.anotherList)
        {
            DoSomething(item);
        }
    }
    else
    {
        // 可选:处理无权限的情况
        LogPermissionDenied(request);
    }
}

进阶优化:批量查询权限

如果你的权限校验方法支持批量查询(比如传入一批Request Id,一次数据库调用返回所有权限结果),这会是性能最优的方案——毕竟多次单条查询不如一次批量查询高效:

// 收集所有Request的唯一标识
var requestIds = requestsList.Select(r => r.Id).ToList();

// 一次数据库调用,获取所有权限结果
var batchPermissionMap = myVar.GetBatchPermissions(requestIds); // 假设返回Dictionary<int, bool>

// 遍历处理,直接用批量查询的结果
foreach (var request in requestsList)
{
    if (batchPermissionMap.TryGetValue(request.Id, out bool hasPerm) && hasPerm)
    {
        foreach (var item in request.anotherList)
        {
            DoSomething(item);
        }
    }
}

注意事项

  • 用字典缓存权限时,尽量用Request的唯一标识(比如Id)作为键,而不是直接用Request对象——避免因为对象哈希值变化或者未正确实现GetHashCode/Equals导致的缓存失效。
  • 如果权限校验是异步方法(比如HasPermissionsAsync),记得用await处理,LINQ筛选时要改成await Task.WhenAll或者异步循环,不要阻塞线程。

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

火山引擎 最新活动