在 C# 中创建和调用异步方法的 lambda 的正确方法
Right way to create and call lambda of async methods in C#
我花了一些时间弄清楚如何在 C# 中“存储”和调用异步 lambda,它基本上是由 运行ning 尝试的。我发现了一些有效而其他方法无效的方法(如下),我阅读了相关内容,但仍然不清楚为什么有些有效而其他无效,有人可以解释为什么并可能添加更好的方法吗?
public static class Program
{
static async Task Main(string[] args)
{
// works fine, everything is printed
Console.WriteLine("Before 1 delay");
await Task.Delay(1000);
Console.WriteLine("After 1 delay");
// works fine, everything is printed
var foo = new Func<Task>(async () =>
{
Console.WriteLine("Before 2 delay");
await Task.Delay(1000);
Console.WriteLine("After 2 delay");
});
await foo.Invoke();
// works fine, everything is printed
var foo2 = new Action(() =>
{
Console.WriteLine("Before 3 delay");
Task.Delay(1000).Wait();
Console.WriteLine("After 3 delay");
});
foo2.Invoke();
// Does not work, just before is printed
var foo3 = new Action(async () =>
{
Console.WriteLine("Before 4 delay");
await Task.Delay(1000);
Console.WriteLine("After 4 delay");
});
foo3.Invoke();
}
}
请注意,该问题与下面的问题不同,即使答案相同,上下文也不同,因为这个问题基本上就是为什么 Action 委托 运行 async 即使与await 在那里,除此之外还有“为什么 .Await() 有效,而 await 不在动作委托中”的“奖励”
异步任务与异步无效
“await” 不等待调用完成
为什么控制台 window 在显示我的输出后立即关闭?
如何阻止 C# 控制台应用程序自动关闭?
// Does not work, just before is printed
// Action-Delegate => "void" does not return the Task, cannot be awaited.
var foo3 = new Action(async () =>
{
Console.WriteLine("Before 4 delay");
await Task.Delay(1000); // Meanwhile, your Program ends!
Console.WriteLine("After 4 delay");
});
foo3.Invoke(); // <- Starts the action "fire&forget"
//Your Program ends BEFORE second WriteLine can be executed.
^^ 查看代码中的注释。如果你在那之后放置任何东西 foo3.Invoke();
阻止你的程序至少再退出一秒钟,你会看到“4 次延迟后”输出。
这基本上是一个 async void Method()
- 这是一个坏主意,除了异步事件处理程序。
请注意,这还有其他副作用。例如,在 Action.
中出现异常的情况下
var foo2 = new Action(() => // _NOT_ async!
{
Console.WriteLine("Before 3 delay");
Task.Delay(1000).Wait(); // Blocking!
Console.WriteLine("After 3 delay");
});
foo2.Invoke(); // Will block. => "works"
你最后一种方法的问题是你用 Action
包装了一个异步 lambda,它描述了一个 void
返回函数。
当 await Task.Delay(1000);
执行时,它告诉运行时在延迟异步完成后安排继续(即该行之后的指令)。
此时委托的调用者无法等待内部异步函数及其延迟,所以这里我们处于async void
调用,操作最终会完成,但不会返回 Task-like
实例。由于调用者无法等待函数终止,它会继续执行直到 Main
方法退出。
一般来说,async void
应该只用于 asynchronous event handlers,因为如您所见,调用者无法正确等待函数完成。
在 C# 中创建和调用异步方法的 lambda 的正确方法
// return a Task!
var wrapper = new Func<Task>(async () =>
{
await SomethingAsync();
});
await wrapper.Invoke();
我花了一些时间弄清楚如何在 C# 中“存储”和调用异步 lambda,它基本上是由 运行ning 尝试的。我发现了一些有效而其他方法无效的方法(如下),我阅读了相关内容,但仍然不清楚为什么有些有效而其他无效,有人可以解释为什么并可能添加更好的方法吗?
public static class Program
{
static async Task Main(string[] args)
{
// works fine, everything is printed
Console.WriteLine("Before 1 delay");
await Task.Delay(1000);
Console.WriteLine("After 1 delay");
// works fine, everything is printed
var foo = new Func<Task>(async () =>
{
Console.WriteLine("Before 2 delay");
await Task.Delay(1000);
Console.WriteLine("After 2 delay");
});
await foo.Invoke();
// works fine, everything is printed
var foo2 = new Action(() =>
{
Console.WriteLine("Before 3 delay");
Task.Delay(1000).Wait();
Console.WriteLine("After 3 delay");
});
foo2.Invoke();
// Does not work, just before is printed
var foo3 = new Action(async () =>
{
Console.WriteLine("Before 4 delay");
await Task.Delay(1000);
Console.WriteLine("After 4 delay");
});
foo3.Invoke();
}
}
请注意,该问题与下面的问题不同,即使答案相同,上下文也不同,因为这个问题基本上就是为什么 Action 委托 运行 async 即使与await 在那里,除此之外还有“为什么 .Await() 有效,而 await 不在动作委托中”的“奖励”
异步任务与异步无效 “await” 不等待调用完成 为什么控制台 window 在显示我的输出后立即关闭? 如何阻止 C# 控制台应用程序自动关闭?
// Does not work, just before is printed
// Action-Delegate => "void" does not return the Task, cannot be awaited.
var foo3 = new Action(async () =>
{
Console.WriteLine("Before 4 delay");
await Task.Delay(1000); // Meanwhile, your Program ends!
Console.WriteLine("After 4 delay");
});
foo3.Invoke(); // <- Starts the action "fire&forget"
//Your Program ends BEFORE second WriteLine can be executed.
^^ 查看代码中的注释。如果你在那之后放置任何东西 foo3.Invoke();
阻止你的程序至少再退出一秒钟,你会看到“4 次延迟后”输出。
这基本上是一个 async void Method()
- 这是一个坏主意,除了异步事件处理程序。
请注意,这还有其他副作用。例如,在 Action.
中出现异常的情况下var foo2 = new Action(() => // _NOT_ async!
{
Console.WriteLine("Before 3 delay");
Task.Delay(1000).Wait(); // Blocking!
Console.WriteLine("After 3 delay");
});
foo2.Invoke(); // Will block. => "works"
你最后一种方法的问题是你用 Action
包装了一个异步 lambda,它描述了一个 void
返回函数。
当 await Task.Delay(1000);
执行时,它告诉运行时在延迟异步完成后安排继续(即该行之后的指令)。
此时委托的调用者无法等待内部异步函数及其延迟,所以这里我们处于async void
调用,操作最终会完成,但不会返回 Task-like
实例。由于调用者无法等待函数终止,它会继续执行直到 Main
方法退出。
一般来说,async void
应该只用于 asynchronous event handlers,因为如您所见,调用者无法正确等待函数完成。
在 C# 中创建和调用异步方法的 lambda 的正确方法
// return a Task!
var wrapper = new Func<Task>(async () =>
{
await SomethingAsync();
});
await wrapper.Invoke();