从内部取消连续链

时间:2014-11-05 00:37:01

标签: c# .net task-parallel-library continuations

我在.NET 4.0上使用C#,并开始用BackgroundWorker替换一些嵌套的Task<T>设置。

&#34;嵌套&#34;就是这种形式:

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回调的角色。根据我的理解,使用Task<T>时的等效内容是ContinueWith()的延续;但是,这并不能让我决定在特定情况下是否实际从控制流程中继续运行。

< - > 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机制。真的有多糟糕?什么是正确的,&#34;惯用的&#34;根据流程中确定的信息取消连续链的方法?

(这个代码在外面有预期的效果,但我认为这是解决使用现有工具的任务的错误方法。我不是在寻找对我的解决方案的批评&#34;但这是正确的方法。这就是为什么我把它放在SO而不是Code Review上。)

1 个答案:

答案 0 :(得分:1)

使用continuation,C#还提供async方法功能。在这个方案中,您的代码看起来像这样:

async Task<bool> Things() { ... }
async Task MoreThings() { ... }

async Task RunStuff()
{
    if (await Things())
    {
        await MoreThings();
    }
}

具体细节取决于您的实施细节。这里重要的是通过asyncawait,C#将自动生成一个状态机,它将抽象所有乏味的东西从处理延续中抽象出来,以便于组织它们。< / p> 编辑:我发现你的实际Things()MoreThings()方法,你可能不想实际转换为async,所以你可以这样做:

async Task RunStuff()
{
    if (await Task.Run(() => Things()))
    {
        await Task.Run(() => MoreThings());
    }
}

这会将您的特定方法包装在异步任务中。

编辑2:有人向我指出我忽略了4.5之前的限制,以下内容应该有效:

void RunStuff()
{
    Task.Factory.StartNew(() => Things()).ContinueWith(task =>
    {
        if (task.Result)
        {
            Task.Factory.StartNew(() => MoreThings());
        }
    });
}

无论如何都是这样的。