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

时间:2012-05-17 03:17:14

标签: c# task-parallel-library multitasking

我有一个包含两个方法的类,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()");
}

2 个答案:

答案 0 :(得分:14)

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

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

Task.Factory.StartNew(MethodNoArguments).ContinueWith(_ => MethodNoArguments())

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

public static Task ContinueWith(this Task task, Action action)
{
    return task.ContinueWith(_ => action());
}

答案 1 :(得分:4)

使用多个continuation时编写干净的代码并不容易,尽管您可以遵循一些规则来使代码更清晰:

  1. 使用svick回答中的简短形式
  2. 避免链接延续。将每个连续的结果存储在单独的变量中,然后在单独的行中调用ContinueWith
  3. 如果延续代码很长,请将其存储在lambda变量中,然后将其保存在lambda中。
  4. 使用类似“Then”方法的扩展方法,使您的代码更清晰。
  5. 您可以将代码更改为更简洁的代码:

            var call1=Task.Factory.StartNew(()=>MethodNoArguments());
            var call2 = call1.ContinueWith(_ => MethodNoArguments());
            call2.Wait();
    

    甚至

            var call1 = Task.Factory.StartNew<Task>(MethodNoArguments);
            var call2 = call1.Then(MethodNoArguments);
            call2.Wait();
    

    Stephen Toub讨论了Then扩展以及其他可以在Processing Sequences of Asynchronous Operations with Tasks

    中清理代码的方法

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

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

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

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