为什么C#允许进行覆盖异步操作? [英] Why does C# allow making an override async?

查看:109
本文介绍了为什么C#允许进行覆盖异步操作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C#中,当您覆盖某个方法时,允许在不使用原始方法的情况下进行覆盖异步操作.这似乎是糟糕的形式.

让我感到疑惑的问题是:我被带去协助进行负载测试问题.在大约500个并发用户的情况下,登录过程将分解为重定向循环. IIS正在记录异常,并显示消息异步模块或处理程序在异步操作仍处于挂起状态时已完成".进行搜索后,我认为有人在滥用async void,但是我对源进行的快速搜索未找到任何内容.

可悲的是,当我应该寻找更像async\s*[^T]之类的东西时,我正在搜索async\s*void(正则表达式搜索)(假设Task并非完全合格.).

我后来发现的是基本控制器中的async override void onActionExecuting.显然,这一定是问题所在.解决该问题(暂时使其同步)解决了该问题.

但是它给我一个问题:为什么在调用代码无法等待时将覆盖标记为异步?

解决方案

当基类(或接口)声明一个返回Task的虚拟方法时,只要您返回Task,就可以覆盖它. async关键字只是对编译器的提示,该编译器将您的方法转换为状态机.尽管编译器确实对您的方法产生了魔力,但编译后的方法仍然返回Task .


对于void虚拟方法,您可以(显然)覆盖一个没有关键字的并在其中启动一个未等待的任务.当您使用async关键字覆盖并在正文中使用await时,会发生这种情况.调用者将不等待创建的任务(因为原始"签名为void).两种情况都相似*:

public override void MyVirtualMethod()
{
    // Will create a non awaited Task (explicitly)
    Task.Factory.StartNew(()=> SomeTaskMethod());  
}

public override async void MyVirtualMethod()
{
    // Will create a non awaited Task (the caller cannot await void)
    await SomeTaskMethod();  
}

斯蒂芬·克雷里(Stephen Cleary)的文章对此有一些注释: >

  • 返回无效值的异步方法有一个特定目的:使异步事件处理程序成为可能.
  • 与异步void相比,您应该更喜欢异步任务.

* SomeTaskMethod的实现,底层框架,SynchronizationContext和其他因素可能并且将导致上述每种方法产生不同的结果.

In C#, when you override a method, it is permitted to make the override async when the original method was not. This seems like poor form.

The problem that makes me wonder is this: I was brought in to assist with a load test problem. At around 500 concurrent users, the login process would break down into a redirect loop. IIS was logging exceptions with the message "An asynchronous module or handler completed while an asynchronous operation was still pending". Some searching led me to think that someone was abusing async void, but my quick searches through the source found nothing.

Sadly, I was searching for async\s*void (regex search) when I should have been looking for something more like async\s*[^T] (assuming Task wasn't fully qualified.. you get the point).

What I later found was async override void onActionExecuting in a base controller. Clearly that had to be the problem, and it was. Fixing that up (making it synchronous for the moment) resolved the problem.

But it left me with a question: Why can you mark an override as async when the calling code could never await it?

解决方案

When the base class (or interface) declares a virtual method that returns a Task, you can override it as long as you return Task. The async keyword is just a hint to the compiler to transform your method into a state machine. Although the compiler does it's black magic on your method, the compiled method still returns a Task.


As for void virtual methods, you can override one without the async keyword (obviously) and start a non-awaited Task within it. That's kind of what happens when you override it with the async keyword and use await in the body. The caller would not await the created Task (since the "original" signature is void). Both cases are similar*:

public override void MyVirtualMethod()
{
    // Will create a non awaited Task (explicitly)
    Task.Factory.StartNew(()=> SomeTaskMethod());  
}

public override async void MyVirtualMethod()
{
    // Will create a non awaited Task (the caller cannot await void)
    await SomeTaskMethod();  
}

Stephen Cleary's article has some notes regarding this:

  • Void-returning async methods have a specific purpose: to make asynchronous event handlers possible.
  • You should prefer async Task to async void.

*The implementation of SomeTaskMethod, the underlying framework, the SynchronizationContext and other factors might and will cause different outcomes for each of the above methods.

这篇关于为什么C#允许进行覆盖异步操作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆