is there a way to break out of the foreach extension method? The "break" keyword doesn't recognize the extension method as a valid scope to break from.
//Doesn't compile
Enumerable.Range(0, 10).ToList().ForEach(i => { System.Windows.MessageBox.Show(i.ToString()); if (i > 2)break; });
Edit: removed "linq" from question
note the code is just an example to show break not working in the extension method... really what I want is for the user to be able to abort processing a list.. the UI thread has an abort variable and the for loop just breaks when the user hits a cancel button. Right now, I have a normal for loop, but I wanted to see if it was possible to do with the extension method.
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;}
});
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;
});
来源:https://stackoverflow.com/questions/3145563/list-foreach-break