C# 从内部取消延续链
我在.NET 4.0上的C#中工作,已经开始用C# 从内部取消延续链,c#,.net,task-parallel-library,continuations,C#,.net,Task Parallel Library,Continuations,我在.NET 4.0上的C#中工作,已经开始用任务替换许多嵌套的BackgroundWorker设置 “嵌套”的形式如下: var secondWorker = new BackgroundWorker(); secondWorker.DoWork += (sender, args) => { MoreThings(); }; var firstWorker = new BackgroundWorker(); firstWorker.DoWork += (sender, args
任务
替换许多嵌套的BackgroundWorker
设置
“嵌套”的形式如下:
var secondWorker = new BackgroundWorker();
secondWorker.DoWork += (sender, args) =>
{
MoreThings();
};
var firstWorker = new BackgroundWorker();
firstWorker.DoWork += (sender, args) =>
{
args.Result = this.Things();
};
firstWorker.RunWorkerCompleted += (sender, args) =>
{
var result = (bool)args.Result;
// possibly do things on UI
if (result) { secondWorker.RunWorkerAsync(); }
};
secondWorker
这里扮演了firstWorker
的回调角色。据我所知,使用任务时的等效方法是使用ContinueWith()
的continuations;但是,这不允许我决定在特定情况下是否从控制流实际运行continuation
A-据我所知,非常不干净-解决方法如下:
var source = new CancellationTokenSource();
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => { return this.Things(); })
.ContinueWith(t =>
{
// do things on UI
if (!t.Result) { source.Cancel(); }
}, CancellationToken.None, TaskContinuationOptions.NotOnFaulted, uiScheduler)
.ContinueWith(t => { this.MoreThings(); }, source.Token);
这种方法是有效的,但从我所看到的所有示例来看,在这种形式下(从延续链中访问CancellationTokenSource
——尽管不使用令牌的任务),它看起来更像是滥用CancellationToken
机制。这到底有多糟糕?根据流中确定的信息,取消延续链的正确“惯用”方法是什么
(外部的代码具有预期的效果,但我认为这是使用现有工具解决任务的错误方法。我不是在寻求对我的“解决方案”的批评,而是寻找正确的方法。这就是为什么我要这样做,而不是代码审查。)继续,C#还提供了async
方法特性。在此方案中,您的代码如下所示:
async Task<bool> Things() { ... }
async Task MoreThings() { ... }
async Task RunStuff()
{
if (await Things())
{
await MoreThings();
}
}
这将在异步任务中包装您的特定方法
编辑2:有人向我指出,我忽略了4.5版本之前的限制,以下内容应该有效:
void RunStuff()
{
Task.Factory.StartNew(() => Things()).ContinueWith(task =>
{
if (task.Result)
{
Task.Factory.StartNew(() => MoreThings());
}
});
}
反正是这样的。这当然是我喜欢的方式,但不幸的是,我们仍然使用.NET 4.0/C#4,所以我还不能使用它。啊,没有注意到4.0的限制。好吧,它还是一样的……你不需要所有取消的东西,只要检查完成任务的结果
,决定是否运行下一个。@TeaDrivenDev如果你安装了.Net 4.0,你可以使用wait
,假设你有C#5.0编译器(VS2012+)。@svick既然你提到了它,我想我以前确实见过。这里的问题是,补丁KB2468871提到的“常见”程度如何,也就是说,如果我可以假设安装在我们客户的机器上(大型企业中相当谨慎的更新行为也是目前阻止我们正确使用.NET 4.5的原因)。但显然,这已经三年了,不是按需修复,所以我们应该是安全的。我会调查的;谢谢。在您的示例中,source.Cancel()
实际上不会做任何事情,因为您没有协同检查是否在第二个ContinueWith
中请求取消。这就是你想要做的吗?@YuvalItzchakov不,这是因为被取消的令牌被传递到最后一个ContinueWith()
调用,而该调用由于被取消而不运行continuation。
void RunStuff()
{
Task.Factory.StartNew(() => Things()).ContinueWith(task =>
{
if (task.Result)
{
Task.Factory.StartNew(() => MoreThings());
}
});
}