【问题标题】:Difference between Func<T, Task> and anonymous async await Action<T>Func<T, Task> 和匿名异步等待 Action<T> 的区别
【发布时间】:2020-01-31 13:45:16
【问题描述】:

我在 ASP.NET Core Blazor 上进行开发,有时我会在 GitHub 上学习一些东西。这个问题与 Blazor 没有严格的关系,但我看到很多 Blazor 开发人员在做我将要解释的事情。

我注意到一些组件接受Action&lt;T&gt; 作为参数,而另一些则接受Func&lt;T, Task&gt;

/* example */

public class MyComponentA : ComponentBase 
{
    [Parameter] public Action<T> OnClick {get; set;}

    //... other methods
}

public class MyComponentB : ComponentBase 
{
    [Parameter] public Func<T, Task> OnClickAsync {get; set;}

    //... other methods
}

我的理解是,您应该将 Action&lt;T&gt; 绑定到 no-async/await 方法,将 Func&lt;T, Task&gt; 绑定到 async/method。到目前为止一切顺利。

但是,我看到有人习惯于将 async/await 匿名函数 传递为 Action&lt;T&gt;,例如 OnClick=@(async (item) =&gt; await Foo(item))。有时,我也将匿名 async/await 函数作为 Action 传递,并且它可以工作。

  • 正确吗?

  • 有什么副作用吗?

  • 调用匿名 async/await 函数的 Action&lt;T&gt; 是异步调用吗?

【问题讨论】:

  • Action 是一个没有返回值的委托; Func 是一个有返回值的委托。您使用哪一个与特定方法是否异步执行无关。
  • @stackoverflow.com/users/884561/kenneth-k 那么为什么有些开发人员会说“现在,使用 Func 我们的组件接受异步方法。UI 线程不会被我们的组件阻塞”。按照您的回答,这句话似乎没有任何意义。似乎 Func 是一种更好的方式来接受 async/await 方法而不使用 async/await 匿名方法。

标签: c# async-await blazor


【解决方案1】:

Action&lt;T&gt; 不允许返回值,只能等待返回awaitable type(通常为TaskTask&lt;T&gt;)的方法。

因此,如果您使用 Action&lt;T&gt; 传递异步方法,它将总是一劳永逸。

使用FuncTask 作为返回值可能等待,具体取决于方法的实现方式。

【讨论】:

  • Fire and Forget 仅适用于异步方法,因为它们在某些时候会放弃对线程的控制,并且如果不等待代码之后它将不会继续。然而,使用同步方法,整个代码将在线程继续运行之前运行,然后执行任何代码。
  • @juharr 是的,也许不是最好的措辞;我会更新的。
  • 在 Blazor 上下文中,等待 Func&lt;T, Task&gt; 可能非常有用,因为它允许开发人员随后触发 StateHasChanged() 以使用适当的函数效果更新 UI。
  • @Rich 我可以请你给我看一个例子吗?谢谢!
  • 我手边没有一个,但想一想——你不知道什么时候触发并忘记调用的结果是完整的,而且你并不真正关心。因为您可以等待从 Func 返回的 Task(虽然老实说,C# 需要 Unit 类型),所以您知道它已经完成并且可以安全地调用 StateHasChanged。
【解决方案2】:

有时,我也将匿名 async/await 函数作为 Action 传递,并且它可以工作。

编译

实际发生的是async lambda 被编译器转换为async void 方法,而async void methods are problematic

正确吗?有什么副作用吗?

这可能是不正确的。

如果委托只是一个“通知”,那么它本质上就是一个事件,async void 通常对于事件是可以接受的。问题是:Blazor 如何知道它的工作已经完成? Blazor does have a SynchronizationContext;但是,它的SynchronizationContext 不是detect async void handlers。因此,当 Blazor 确实有更多工作要做时,它可能会决定它的工作已经完成。

调用匿名 async/await 函数的 Action 是异步调用吗?

是的,但它是async void,所以它不会出现异步。例如,委托调用者无法知道委托何时完成执行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-12
    • 1970-01-01
    相关资源
    最近更新 更多