如何在 C# 中的 ContinueWith 之前使用 Delay Task.ContineWith?

How to do Task.ContineWith using a Delay before the ContinueWith in C#?

我知道我可以像这样执行一个简单的延迟任务:

Task.Delay(iDelayInMilliseconds).ContinueWith(() => SomeMethod());

我可以像这样将两种不同的方法链接为顺序任务:

Task.Run(() => SomeMethod()).ContinueWith(() => AnotherMethod());

我想不通的是这样的:

Task.Run(() => SomeMethod()).Delay(iDelayInMilliseconds).ContinueWith(() => AnotherMethod());

实际上,我希望 SomeMethod() 到 运行,然后是延迟,然后是 AnotherMethod()。

谁能帮我解决这个问题?

Task.Run(async () =>
{
    SomeMethod();
    await Task.Delay(iDelayInMilliseconds);
}).ContinueWith(cw => AnotherMethod());

这里,我们实际上需要等待内部Task(即Task.Delay(iDelayInMilliseconds))完成,否则Task[= Task.Run() 编辑的 33=] 将 return 立即将其 Status 设置为 RanToCompletion

当然,如果这不需要在ThreadPool线程上运行,你可以一并删除Task.Run()

// ...
SomeMethod();
await Task.Delay(iDelayInMilliseconds);
AnotherMethod();

..这意味着您必须将父方法标记为 async 并使用 return Task<T> 而不是 TTask 如果它 returns void.

我建议为此查看 Microsoft 的 Reactive Framework。它比任务更强大,恕我直言,可以像 LINQ 查询一样使用,并且很容易与任务和异步操作互操作。

在您的情况下,您的代码可以如下所示:

void Main()
{
    var iDelayInMilliseconds = 4000;

    IObservable<int> query =
        from x in Observable.Start(() => SomeMethod())
        from y in Observable.Timer(TimeSpan.FromMilliseconds(iDelayInMilliseconds))
        from z in Observable.Start(() => AnotherMethod())
        select x + z;

    IDisposable subscription = query.Subscribe(w => Console.WriteLine(w));
}

public int SomeMethod() => 1;
public int AnotherMethod() => 2;

这需要 4,000 毫秒并在控制台上生成 3

如果您想提前停止查询,只需在 subscription 上调用 .Dispose()

如果您的一些方法是 async 并且您想要返回 Task<int> 那么您可以这样做:

void Main()
{
    var iDelayInMilliseconds = 4000;

    IObservable<int> query =
        from x in Observable.StartAsync(() => SomeMethod())
        from y in Observable.Timer(TimeSpan.FromMilliseconds(iDelayInMilliseconds))
        from z in Observable.Start(() => AnotherMethod())
        select x + z;

    Task<int> task = query.ToTask();

    Console.WriteLine(task.Result);
}

public async Task<int> SomeMethod() => await Task.Run(() => 1);
public int AnotherMethod() => 2;

这仍然会以正确的延迟产生正确的结果。

只需 NuGet "System.Reactive" 并将 using System.Reactive.Linq; 添加到您的代码中以使其正常工作。