Task.ContinueWith方法需要任务参数吗?

Jas*_*aat 7 c# multitasking task-parallel-library

我有一个有两个方法的类,Load()和Process().我希望能够将这些单独作为后台任务或按顺序运行.我喜欢ContinueWith()语法,但我无法让它工作.我必须在我继续的方法上获取一个Task参数,并且在初始方法上不能有Task参数.

我想在没有lambda表达式的情况下做到这一点,但我是不是使用它们,强制在其中一个方法上创建任务参数,或者创建第三个方法LoadAndProcess()?

void Run()
{
    // doesn't work, but I'd like to do it
    //Task.Factory.StartNew(MethodNoArguments).ContinueWith(MethodNoArguments);

    Console.WriteLine("ContinueWith");
    Task.Factory.StartNew(MethodNoArguments).ContinueWith(MethodWithTaskArgument).Wait();

    Console.WriteLine("Lambda");
    Task.Factory.StartNew(() => { MethodNoArguments(); MethodNoArguments(); }).Wait();

    Console.WriteLine("ContinueWith Lambda");
    Task.Factory.StartNew(MethodNoArguments).ContinueWith(x => { 
            MethodNoArguments(); 
        }).Wait();
}

void MethodNoArguments()
{
    Console.WriteLine("MethodNoArguments()");
}

void MethodWithTaskArgument(Task t = null)
{
    Console.WriteLine("MethodWithTaskArgument()");
}
Run Code Online (Sandbox Code Playgroud)

svi*_*ick 14

在所有重载中ContinueWith(),第一个参数是一个带有a的委托Task,因此您无法将无参数委托传递给它.

我认为使用lambdas非常好,并且不会影响可读性.并且代码中的lambda不必要地冗长:

Task.Factory.StartNew(MethodNoArguments).ContinueWith(_ => MethodNoArguments())
Run Code Online (Sandbox Code Playgroud)

或者,正如Cory Carson在评论中指出的那样,你可以写一个扩展方法:

public static Task ContinueWith(this Task task, Action action)
{
    return task.ContinueWith(_ => action());
}
Run Code Online (Sandbox Code Playgroud)


Pan*_*vos 5

使用多个延续时编写干净的代码并不是那么容易,尽管您可以遵循一些规则来使代码更干净:

  1. 使用 svick 答案中的较短形式
  2. 避免链接延续。将每个延续的结果存储在一个单独的变量中,然后在单独的行中调用 ContinueWith
  3. 如果继续代码很长,请将其存储在 lambda 变量中,然后使用 lambda 继续。
  4. 使用像“ Then ”这样的扩展方法使您的代码更加简洁。

您可以将代码更改为这样的内容,这样稍微简洁一些:

        var call1=Task.Factory.StartNew(()=>MethodNoArguments());
        var call2 = call1.ContinueWith(_ => MethodNoArguments());
        call2.Wait();
Run Code Online (Sandbox Code Playgroud)

甚至

        var call1 = Task.Factory.StartNew<Task>(MethodNoArguments);
        var call2 = call1.Then(MethodNoArguments);
        call2.Wait();
Run Code Online (Sandbox Code Playgroud)

Stephen Toub 在使用任务处理异步操作序列中讨论了 Then 扩展和其他清理代码的方法

这个问题在 C# 4 中得到了很好的解决。 在 C# 5 中,您可以使用 async/await 关键字创建看起来像原始同步版本的干净代码,例如:

    static async Task Run()
    {
        await MethodNoArguments();
        await MethodNoArguments();
    }

    static async Task MethodNoArguments()
    {
        await Task.Run(()=>Console.WriteLine("MethodNoArguments()"));
    }
Run Code Online (Sandbox Code Playgroud)

Visual Studio 11 和 .NET 4.5 具有 Go Live 许可证,因此您可能可以立即开始使用它们。

您可以在 C# 4 中使用 Async CTP 来实现相同的结果。您可以在生产中使用 Async CTP,因为它具有上线许可证。缺点是当您迁移到 .NET 4.5 时,由于 CTP 和 .NET 4.5 之间的差异(例如,CTP 具有 TaskEx.Run 而不是 Task.Run),您必须对代码进行一些小的更改。