List ForEach break

人盡茶涼 提交于 2019-11-29 13:09:55

It's probably more accurate to call this a List<T> Foreach vs. a LINQ one.

In either case though no there is no way to break out of this loop. Primarily because it's not actually a loop per say. It's a method which takes a delegate that is called inside a loop.

Creating a ForEach with break capability is fairly straight forward though

public delegate void ForEachAction<T>(T value, ref bool doBreak);
public static void ForEach<T>(this IEnumerable<T> enumerable, ForEachAction<T> action) {
    var doBreak = false;
    foreach (var cur in enumerable) {
        action(cur, ref doBreak);
        if (doBreak) {
            break;
        }
    }
}

You could then rewrite your code as the following

Enumerable.Range(0,10)
    .ForEach((int i,ref bool doBreak) => {
        System.Windows.MessageBox.Show(i.ToString()); 
        if ( i > 2) {doBreak = true;}
    });

I recommend using TakeWhile.

Enumerable.Range(0, 10).TakeWhile(i => i <= 2).ToList().ForEach(i => MessageBox.Show(i.ToString()));

Or, using Rx:

Enumerable.Range(0, 10).TakeWhile(i => i <= 2).Run(i => MessageBox.Show(i.ToString()));

Why not use Where?

Enumerable.Range(0, 10).Where(i => i <= 2).ToList().ForEach(...)

Try a "return" statement instead of "break"; it's a delegate function and not a real loop.

Try:

Enumerable.Range(0, 10).ToList().ForEach(i => { System.Windows.MessageBox.Show(i.ToString()); if (i > 2) return; });

Why not use foreach ? ...

PS: Just kidding and, as you mentionned, I understand the idea of trying to see how to do it with Linq (and googled here for same reason) ... now for maintenance/readiness reasons in production code guess a simple foreach is good enough sometimes.

For myself, I used Linq Select + FirstOrDefault. Transform "each" in the list but since we are asking for the First, it will stop transforming them after finding the first one that matches.

var thingOption = list.Select(thing => AsThingOption(thing))
.FirstOrDefault(option => option.HasValue) ?? Option.None<MyThing>;

As you can see I'm transforming each thing into an Option and my method AsThingOption may succeed at transforming and when it does we stop iterating over the list. If the conditions inside AsThingOption method never succeed at transforming, then end result is None.

Hope that helps!

Why not throw new Exception("Specific message") or use a boolean flag?

DataTable dt = new DataTable();
bool error = false;

try
{
    dt.AsEnumerable().ToList().ForEach(dr =>
    {
        if (dr["Col1"].ToString() == "")
        {
            error = true;
            throw new Exception("Specific message");
        }
        else 
            // Do something
    });
}
catch (Exception ex)
{
    if (ex.Message == "Specific message" || error) 
        // do something
    else
        throw ex;
}

I have a case where I need to loop actions until a condition is false and each action can modify the value used to track the condition. I came up with this variation of .TakeWhile(). The advantage here is that each item in the list can participate in some logic, then the loop can be aborted on a condition not directly related to the item.

new List<Action> {
    Func1,
    Func2
}.TakeWhile(action => {
    action();
    return _canContinue;
});
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!