Ginandi
Ginandi

Reputation: 853

How to stop execution of a method from within a delegate passed to it and executed by it

I am trying to write a method which receives a delegate, and executes that delegate in a loop. That's not very hard, for example:

public static void RunInLoop<T>(IEnumerable<T> someCollection, 
                                 Action<T> action)
{           
        foreach (var item in someCollection)
        {
                action(item);
        }
}

However, let's say I would like to give the user of RunInLoop means of doing something like break, that is - stop the execution of the loop (or just simply return from RunInLoop).

What I thought about:

  1. Writing a method called Break() - which throws a (private) exception, and then surround action(item) with try catch, and if I catch my (private) exception- just return. This is not so good if the delegate passed catches Exception.

  2. Run the foreach in a new thread, and implement Break() by killing the current thread. Among other reasons, this is not good when using my method in a UI based application (like Silverlight), where sometimes execution must occur in the UI thread.

  3. Another suggestion I got was to receive an extra delegate, with a condition that I will check at the end of each execution. I don't like that either because it is not intuitive for the user, and limits the break to the end of the iteration. This is my last resort for now though.

So no good solution I could find yet. Any suggestions/directions?

Upvotes: 3

Views: 1924

Answers (2)

Dene B
Dene B

Reputation: 496

Could you not just use a static/member variable that is a bool.

Action
{
    ...
    foreach
        if (!s_KeepGoing)
            break
    ...
}

Or if you want flexibility to specify the bool then let the Action take a ref to a bool as a second parameter of a delegate, and check the bool as above.

public delegate void MyDelegate<in T>(T type, ref bool keepGoing);

public static void RunInLoop<T>(IEnumerable<T> someCollection, 
                                 MyDelegate<T> action)
{           
        foreach (var item in someCollection)
        {
                action(item, ref s_AnotherKeepGoing);
        }
}

Upvotes: 0

Servy
Servy

Reputation: 203823

public static void RunInLoop<T>(IEnumerable<T> someCollection, 
                                 Func<T, bool> action)
{           
        foreach (var item in someCollection)
        {
                if(action(item))
                     break;
        }
}

Have the "action" (should rename it to func if you make this change) return a boolean value indicating whether or not you should continue.

It's also worth mentioning that your origional method is just a ForEach extension method. Here is a blog post by Eric Lippert which states why it was intentionally omitted from the framework and why it's really not a good practice (granted a lot of people use it anyway).

Upvotes: 3

Related Questions