我有一个异步函数,为了简单起见,我们就这样吧:
static async Task TestTask(object? _)
{
Console.WriteLine("2");
await Task.Delay(500);
Console.WriteLine("3");
}
我想将此函数的执行封装在一个任务中,我可以在稍后的某个时间点或在不直接了解该函数的代码中的某个位置启动该任务。我一直在尝试几种方法来进行这种封装,包括:
static Task GetTask1() =>
new(async () => await TestTask(null));
static Task GetTask2() =>
new(() => Task.Factory.StartNew(async _ => await TestTask(null), null,
TaskCreationOptions.AttachedToParent));
static Task GetTask3() =>
new(() => Task.Factory.StartNew(TestTask, null,
TaskCreationOptions.AttachedToParent));
在程序中使用时,如以下示例所示,函数会启动,但在函数的第一个“等待”处被视为“完成”:
Console.WriteLine("1");
// Create the task to hold on to for later.
Task toStart = GetTask3();
// Later (or elsewhere), start the task.
toStart.Start();
await Task.WhenAll(toStart);
Console.WriteLine("4");
这会导致控制台仅输出 1、2 和 4。
我想我明白为什么 GetTask1 和 GetTask2 不起作用(由于嵌套异步执行),但似乎 GetTask3 应该通过将正在运行的任务附加到稍后启动的父任务来工作。
为什么这不起作用?正确的方法是什么?
您可以非常简单地使用
Func<Task>
来包裹它:
public static class Program
{
public static async Task Main(string[] args)
{
var task = GetSomeTask();
Console.WriteLine("1");
await task.Invoke();
Console.WriteLine("4");
}
private static Func<Task> GetSomeTask()
{
return MyMethod;
}
private static async Task MyMethod()
{
Console.WriteLine("2");
await Task.Delay(500);
Console.WriteLine("3");
}
}
输出:
1
2
3
4