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

C#最佳实践:如何在循环调用的Action<>回调中实现break?

自定义ForEach循环提前终止的最佳实践

针对你实现的ForEachEdge方法,要支持回调中提前终止循环,下面分析各方案并给出最优实践:

方案1:回调返回状态值(推荐)

将回调类型从Action<Edge>改为Func<Edge, bool>,让回调返回布尔值表示是否继续遍历——返回true继续,false终止循环。这种设计和.NET原生API(如Enumerable.TakeWhile、List.Exists)的语义一致,符合终端开发者的直觉。

修改后的方法实现

public void ForEachEdge(in Vertex vertex, Func<Edge, bool> callback)
{
    var edge = GetEdge(vertex.BaseEdgeIndex);
    do
    {
        // 回调返回false时直接终止循环
        if (!callback.Invoke(edge))
            break;
        edge = GetEdge(edge.GetNext(vertex.Index));
    } while (edge.Index != vertex.BaseEdgeIndex);
}

调用示例

ForEachEdge(edge.Vertex0Index, (e) =>
{
    if (inEdge.AreConnectingSameVertices(e))
    {
        // 返回false跳出循环
        return false;
    }
    // 执行正常遍历逻辑
    return true;
});

方案2:传入ref bool参数

通过ref bool stopEnumerating参数让回调修改外部变量的状态,循环中每次检查该变量决定是否终止。这种方式可行,但需要终端开发者额外维护一个外部变量,容易出现初始化遗漏或状态污染的问题,可读性和简洁性不如返回值方案。

示例代码

public void ForEachEdge(in Vertex vertex, Action<Edge, ref bool> callback)
{
    bool stop = false;
    var edge = GetEdge(vertex.BaseEdgeIndex);
    do
    {
        callback.Invoke(edge, ref stop);
        if (stop)
            break;
        edge = GetEdge(edge.GetNext(vertex.Index));
    } while (edge.Index != vertex.BaseEdgeIndex);
}

// 调用
bool stop = false;
ForEachEdge(edge.Vertex0Index, (e, ref s) =>
{
    if (inEdge.AreConnectingSameVertices(e))
    {
        s = true;
    }
});

不推荐的方案

  • 抛出异常:用异常控制正常流程是反模式,会严重影响性能,且不符合异常的语义(异常应仅用于错误场景)。
  • 包装类传递状态:用自定义类包装bool值的方式,本质和ref参数类似,但会增加不必要的代码复杂度,完全没必要。

总结

优先选择回调返回状态值的方案,它语义清晰、代码简洁,完全贴合.NET开发者对遍历API的使用预期,是最符合终端开发者直觉的实现方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 23:36:16