Home > database >  C# best practice: "break" from within Action<> callback called in a loop?
C# best practice: "break" from within Action<> callback called in a loop?

Time:08-17

I had to write my own foreach method for various reasons. This resembles an IEnumerable foreach statement:

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

I'm using it like so but I wish to be able to "break" out of the entire loop:

ForEachEdge(edge.Vertex0Index, (e) =>
{
    if (inEdge.AreConnectingSameVertices(e))
    {
        // break out of inner while loop here ...
    }
});

What would be best practice to break?

  1. Return a status value?
  2. Pass a "ref bool stopEnumerating" parameter in? (requires class instance to wrap it in, right?)
  3. Your thoughts ...

I'm mostly concerned about what end users (developers) would expect in such a case.

CodePudding user response:

the ref parameter method won't be as clean as a return value indicating continuation status. You would have to switch to a Func<Edge, bool>

Func<Edge, bool> callback;
...
if (callback.Invoke(edge)) {
   /// do your break logic
}

CodePudding user response:

I decided that (for now) I'll go with a Predicate<> rather than Action<>:

public void ForEachEdge(in Vertex vertex, Predicate<Edge> callback)
{
    var edge = GetEdge(vertex.BaseEdgeIndex);
    do
    {
        if (callback.Invoke(edge))
            break;
        
        edge = GetEdge(edge.GetNextRadialEdgeIndex(vertex.Index));
    } while (edge.IsValid && edge.Index != vertex.BaseEdgeIndex);
}

Which makes the user's code look like this:

ForEachEdge(edge.Vertex0Index, e =>
{
    if (inEdge.AreConnectingSameVertices(e))
    {
        // found it, do something, then exit loop
        return true;
    }
    
    // continue with next item
    return false;
});
  • Related