我是C#的新手,我知道这是一个老问题,但是我想出了以下解决方案:
用法:
const string topLoopLabel = "topLoop";
Loop.ForEach(fooList, (fooItem, index, next) =>
{
Loop.For(0, (i) => i < bar.Length, (i) => i++, (index, next) =>
{
if (condition)
{
next(topLoopLabel);
}
});
}, topLoopLabel);
在引擎盖下:
static class Loop {
public delegate void Continue(string? label = null);
public delegate void IndexedIterationHandler(int index, Continue next);
public delegate void ListIterationHandler<T>(T item, int index, Continue next);
private static Continue next = (label) => {
throw new CancelledIterationException { Label = label };
};
public static void For(int initialIndex, Func<int, bool> indexCondition, Func<int, int> iterator, IndexedIterationHandler iterationHandler, string? label = null)
{
for (int i = initialIndex; indexCondition(i);)
{
OnIteration(() => iterationHandler(i, next));
i = iterator(i);
}
}
public static void ForEach<T>(IList<T> list, ListIterationHandler<T> iterationHandler, string? label = null)
{
for (int i = 0; i < list.Count; i++)
{
OnIteration(() => iterationHandler(list[i], i, next));
}
}
private static void OnIteration(Action loopBody)
{
try
{
loopBody();
}
catch (CancelledIterationException e)
{
if (!String.IsNullOrEmpty(e.Label) && !String.Equals(e.Label, e))
{
throw;
}
}
}
[Serializable()]
class CancelledIterationException : Exception
{
public required string? Label { get; init; }
}
}
优点:
- 没有goto或多个返回语句
- 没有临时变量
- 不同的循环可以轻松组合
- 易于理解
- 不需要为每个循环添加标签
缺点:
- 正如您在底层看到的,异常被用来修改程序流程,这是一种反模式
- 如果在顶层循环中调用下一个函数,并且该字符串参数不等于顶层循环的标签,则异常将无法捕获。