让我们以诚实的态度开始吧。我不是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);
}
}
但看看那不必要的重复。
感谢您的考虑。
答案 0 :(得分:14)
我没有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);
}
}
}
此方法将任务放在数组中。如果需求发生变化,需要更多任务,那么数组定义会变长,但其余代码保持不变。好的代码使用循环来执行重复性任务,而不是像原始帖子中那样进行大量的复制和粘贴。
答案 1 :(得分:1)
准备代码(黑客入侵)
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);
}
}
}
答案 2 :(得分:0)
简单方法......
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);
}
}
}
答案 3 :(得分:0)
和@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关键字。
答案 4 :(得分:-2)
您可以在try / catch语句中简单地包围if
块,并在取消待处理时抛出异常。
伪代码:
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()
}
}
}