10

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

2 回答 2

19

在 的所有重载中ContinueWith(),第一个参数是一个接受 a 的委托Task,因此您不能将无参数委托传递给它。

我认为使用 lambdas 非常好,并且不会损害可读性。而且您的代码中的 lambda 是不必要的冗长:

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

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

public static Task ContinueWith(this Task task, Action action)
{
    return task.ContinueWith(_ => action());
}
于 2012-05-17T10:02:12.770 回答
5

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

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

你可以把你的代码改成这样,这样更简洁:

        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 扩展和其他可以清理代码的方法

这个问题在 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,因为它具有上线许可证。不利的一面是,由于 CTP 和 .NET 4.5 之间的差异(例如,CTP 具有 TaskEx.Run 而不是 Task.Run),当您迁移到 .NET 4.5 时,您必须对代码进行一些小的更改。

于 2012-05-17T11:29:33.150 回答