在这种情况下,有比GOTO更好的方法吗?
本文关键字:方法 更好 GOTO 这种情况下 有比 | 更新日期: 2023-09-27 18:03:15
让我们诚实地开始吧。我不是goto
的粉丝,但我也不喜欢一遍又一遍地重复我的代码。不管怎样,我碰到了这个场景。这是不寻常的,但也不是独一无二的。我不禁想知道这对goto
来说是不是一个好情况。有没有更好的办法?
public Task Process(CancellationTokenSource token)
{
await SpinUpServiceAsync();
foreach (var item in LongList())
{
if (token.IsCancellationRequested) goto cancel;
await LongTask1(item);
if (token.IsCancellationRequested) goto cancel;
await LongTask2(item);
if (token.IsCancellationRequested) goto cancel;
await LongTask3(item);
if (token.IsCancellationRequested) goto cancel;
await LongTask4(item);
if (token.IsCancellationRequested) goto cancel;
await LongTask5(item);
continue;
cancel:
{
Log($"Cancelled during {item}");
await SpinDownServiceAsync();
return;
}
}
}
这是我看到的下一个最佳选择:
public Task Process(CancellationTokenSource token)
{
await SpinUpServiceAsync();
foreach (var item in LongList())
{
if (token.IsCancellationRequested)
{
Log($"Cancelled during {item}");
await SpinDownServiceAsync();
return;
}
await LongTask1(item);
if (token.IsCancellationRequested)
{
Log($"Cancelled during {item}");
await SpinDownServiceAsync();
return;
}
await LongTask2(item);
if (token.IsCancellationRequested)
{
Log($"Cancelled during {item}");
await SpinDownServiceAsync();
return;
}
await LongTask3(item);
if (token.IsCancellationRequested)
{
Log($"Cancelled during {item}");
await SpinDownServiceAsync();
return;
}
await LongTask4(item);
if (token.IsCancellationRequested)
{
Log($"Cancelled during {item}");
await SpinDownServiceAsync();
return;
}
await LongTask5(item);
}
}
但是看看那些不必要的重复。
谢谢您的考虑。
我没有LongTask1-5的确切类型,但我会这样做。
public Task Process(CancellationTokenSource token)
{
SOMETYPE[] tasks = new SOMETYPE[] {LongTask1, LongTask2, LongTask3, LongTask4, LongTask5};
await SpinUpServiceAsync();
foreach (var item in LongList())
{
foreach(var task in tasks){
if (token.IsCancellationRequested) {
Log($"Cancelled during {item}");
await SpinDownServiceAsync();
return;
}
await task(item);
}
}
}
这种方法将任务放在一个数组中。如果需求发生变化,并且需要更多的任务,那么数组定义会变长,但其余代码保持不变。好的代码使用循环来完成重复的任务,而不是大量的复制和粘贴,比如在原来的帖子中。
好的,这是我的新版本(它可以编译)
准备代码(黑客)
class TypeOfItem { }
async Task LongTask1(TypeOfItem item) { }
async Task LongTask2(TypeOfItem item) { }
async Task LongTask3(TypeOfItem item) { }
async Task LongTask4(TypeOfItem item) { }
async Task LongTask5(TypeOfItem item) { }
async Task SpinUpServiceAsync() { }
async Task SpinDownServiceAsync() { }
IEnumerable<TypeOfItem> LongList() { yield break; }
void Log(string text) { }
和解决方案:
private async Task<bool> CancelAt(TypeOfItem item)
{
Log($"Cancelled during {item}");
await SpinDownServiceAsync();
return false; // cancel
}
public async Task<bool> Process(CancellationTokenSource token)
{
await SpinUpServiceAsync();
foreach (var item in LongList())
{
if (token.IsCancellationRequested) return await CancelAt(item);
await LongTask1(item);
if (token.IsCancellationRequested) return await CancelAt(item);
await LongTask2(item);
if (token.IsCancellationRequested) return await CancelAt(item);
await LongTask3(item);
if (token.IsCancellationRequested) return await CancelAt(item);
await LongTask4(item);
if (token.IsCancellationRequested) return await CancelAt(item);
await LongTask5(item);
}
return true; // all done
}
@codenoire:很好的解决方案,但需要一些修复…: -)
public async Task Process(CancellationTokenSource token)
{
var tasks = new Func<TypeOfItem, Task>[] { LongTask1, LongTask2, LongTask3, LongTask4, LongTask5 };
await SpinUpServiceAsync();
foreach (var item in LongList())
{
foreach (var task in tasks)
{
if (token.IsCancellationRequested)
{
Log($"Cancelled during {item}");
await SpinDownServiceAsync();
return;
}
await task(item);
}
}
}
与@codenoir非常相似,但我更喜欢这样写:
private Action<TypeItem>[] _longTasks = new Action<TypeItem>[]
// Not sure about the type
// that could be also something like Func<TypeItem, Task>
{
LongTask1,
LongTask2,
LongTask3,
LongTask4,
LongTask5
};
public async Task Process(CancellationTokenSource token)
{
await SpinUpServiceAsync();
foreach (var item in LongList())
foreach (var longTask in _longTasks)
{
if (token.IsCancellationRequested)
return Cancel(item);
await longTask(item);
}
}
private async Task Cancel(TypeItem item)
{
Log($"Cancelled during {item}");
await SpinDownServiceAsync();
}
似乎你在你的方法中也缺少async关键字。
简单的方法…
public async Task Process(CancellationTokenSource token)
{
await SpinUpServiceAsync();
bool cancel;
YourObject item;
foreach (var i in LongList())
{
item = i;
cancel = true;
if (token.IsCancellationRequested) break;
await LongTask1(item);
if (token.IsCancellationRequested) break;
await LongTask2(item);
if (token.IsCancellationRequested) break;
await LongTask3(item);
if (token.IsCancellationRequested) break;
await LongTask4(item);
if (token.IsCancellationRequested) break;
await LongTask5(item);
cancel = false;
}
if (cancel)
{
Log($"Cancelled during {item}");
await SpinDownServiceAsync();
return;
}
}
…清洁…
public async Task Process(CancellationTokenSource token)
{
var tasks = new Func<YourItem, Task>[] { LongTask1, LongTask2, LongTask3, LongTask4, LongTask5 };
await SpinUpServiceAsync();
foreach (var item in LongList())
{
foreach(var task in tasks)
{
if (token.IsCancellationRequested)
{
Log("Cancelled during {item}");
await SpinDownServiceAsync();
return;
}
await task(item);
}
}
}
您可以简单地在try/catch语句中包围if
s块,并在等待取消时抛出异常。
伪代码:
function {
try {
for (loop conditions) {
do_stuff_or_throw_exception1();
do_stuff_or_throw_exception2();
...
do_stuff_or_throw_exceptionN();
}
catch (exception) {
log_stuff();
shut_down()
}
}
}