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

我在.NET 4.0上的C#中工作,已经开始用
任务
替换许多嵌套的
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());
        }
    });
}