列出 ForEach 休息时间
Posted
技术标签:
【中文标题】列出 ForEach 休息时间【英文标题】:List ForEach break 【发布时间】:2010-06-29 23:40:54 【问题描述】:有没有办法摆脱 foreach 扩展方法? “break”关键字无法将扩展方法识别为有效的中断范围。
//Doesn't compile
Enumerable.Range(0, 10).ToList().ForEach(i => System.Windows.MessageBox.Show(i.ToString()); if (i > 2)break; );
编辑:从问题中删除“linq”
请注意,代码只是一个示例,显示 break 在扩展方法中不起作用……我真正想要的是让用户能够中止处理列表。UI 线程有一个 abort 变量和 for当用户点击取消按钮时,循环就会中断。现在,我有一个正常的 for 循环,但我想看看是否可以使用扩展方法。
【问题讨论】:
How do i exit a List<string>.ForEach loop when using an anonymous delegate?的可能重复 【参考方案1】:将其称为 List<T>
Foreach 与 LINQ 可能更准确。
在这两种情况下,虽然没有,但没有办法跳出这个循环。主要是因为它实际上并不是一个循环。这是一个方法,它接受一个在循环内调用的委托。
创建一个具有中断功能的 ForEach 是相当简单的
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;
然后你可以重写你的代码如下
Enumerable.Range(0,10)
.ForEach((int i,ref bool doBreak) =>
System.Windows.MessageBox.Show(i.ToString());
if ( i > 2) doBreak = true;
);
【讨论】:
【参考方案2】:我推荐使用TakeWhile。
Enumerable.Range(0, 10).TakeWhile(i => i <= 2).ToList().ForEach(i => MessageBox.Show(i.ToString()));
或者,使用Rx:
Enumerable.Range(0, 10).TakeWhile(i => i <= 2).Run(i => MessageBox.Show(i.ToString()));
【讨论】:
【参考方案3】:为什么不使用Where
?
Enumerable.Range(0, 10).Where(i => i <= 2).ToList().ForEach(...)
【讨论】:
【参考方案4】:尝试使用“return”语句而不是“break”;它是一个委托函数,而不是一个真正的循环。
试试:
Enumerable.Range(0, 10).ToList().ForEach(i => System.Windows.MessageBox.Show(i.ToString()); if (i > 2) return; );
【讨论】:
【参考方案5】:为什么不使用 foreach
? ...
PS:开个玩笑,正如你所提到的,我理解尝试查看如何使用 Linq 执行此操作的想法(出于同样的原因在此处搜索)......现在出于生产代码中维护/准备就绪的原因,猜测一个简单的foreach
有时就足够了。
【讨论】:
【参考方案6】:对于我自己,我使用了 Linq Select + FirstOrDefault。转换列表中的“每个”,但由于我们要求的是第一个,所以它会在找到第一个匹配的之后停止转换它们。
var thingOption = list.Select(thing => AsThingOption(thing))
.FirstOrDefault(option => option.HasValue) ?? Option.None<MyThing>;
如您所见,我正在将每个事物转换为选项,并且我的方法 AsThingOption 可能会成功转换,当它成功时,我们会停止迭代列表。如果 AsThingOption 方法中的条件从未成功转换,则最终结果为 None。
希望有帮助!
【讨论】:
【参考方案7】:为什么不throw new Exception("Specific message")
或使用布尔标志?
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;
【讨论】:
【参考方案8】:我有一个案例,我需要循环操作直到条件为假,并且每个操作都可以修改用于跟踪条件的值。我想出了.TakeWhile() 的这种变体。这里的好处是列表中的每个项目都可以参与一些逻辑,然后可以在与项目没有直接关系的条件下中止循环。
new List<Action>
Func1,
Func2
.TakeWhile(action =>
action();
return _canContinue;
);
【讨论】:
以上是关于列出 ForEach 休息时间的主要内容,如果未能解决你的问题,请参考以下文章
XSLT1,Muenchian 分组,在 foreach 循环中列出分组节点