为什么C#允许您进行重写异步?


16

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

使我想到这一点的例子是这样-我是来协助进行负载测试问题的。在大约500个并发用户的情况下,登录过程将在重定向循环中分解。IIS正在记录异常,并显示消息“异步模块或处理程序在异步操作仍处于挂起状态时已完成”。一些搜索使我认为有人在滥用async void,但是我快速搜索源却找不到任何东西。

可悲的是,当我本应寻找诸如“ async \ s [^ T]”之类的东西时,我正在搜索“ async \ svoid”(正则表达式搜索)(假设Task尚未完全合格……您明白了)。

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

回到问题:为什么当调用代码永远无法等待覆盖时,为什么还要将覆盖标记为异步?



究竟是什么阻止调用者等待重写的方法?我没有障碍。
马丁·马特

@MartinMaat您只能等待返回的方法Task
德里克·埃尔金斯

也许这是我没注意到的一个好地方。我必须检查一下,但是我不记得关于在不等待的情况下调用非异步方法的VS警告。
彼得·拉康伯(Peter T. LaComb)

Answers:


16

异步关键字允许的方法使用await在其定义内的语法。我可以await在任何返回Task类型的方法上使用,无论它是否是异步方法。

void是异步方法的合法(尽管不鼓励使用)返回类型,那么为什么不允许使用它呢?从外部看,async没有启用您没有它做不到的任何事情。您遇到麻烦的方法可能被编写为在没有异步的情况下表现完全相同。它的定义将更加冗长。

给呼叫者,一个async T方法是一个正常的方法,该方法返回T(其被限制为voidTask,或Task<A>)。它是一个异步方法不是该接口的一部分。请注意,以下代码是非法的:

interface IFoo {
    async void Bar();
}

它(或抽象类中的类似代码)在VS2012中产生以下错误消息:

'async'修饰符只能在具有语句主体的方法中使用

如果我确实打算让接口或父类中的方法通常是异步的,那么我将无法使用它async来进行通信。如果我想用await语法实现它,我将需要能够有一个异步重写方法(在父类的情况下)。


1
您根本没有提到override,但这就是问题所在。
内森·塔吉

5
@NathanTuggy答案的全部要点是,async不更改方法的接口,仅更改其定义在语法上允许的内容,因此,是否覆盖是完全不相关的。
德里克·埃尔金斯

1
说明这一点,而不是假设每个人都已经知道所有相关内容。
内森·塔吉

2
@NathanTuggy我觉得我已经解释了。您可以问一个关于您感到困惑的特定问题,还是您想像另一个困惑的人会问?我唯一想补充的一点是要指出,async修饰符只能应用于实现。您不能在接口中声明方法异步,例如,强调方法是否异步不是接口的一部分。
德里克·埃尔金斯

5
我的意思是将解释放在答案中。从长远来看,这不是评论。
内森·塔吉

10

async关键字的唯一目的是使该函数体内的关键字成为await。这是必需的,以便添加等待功能不会破坏现有代码。Microsoft决定使用“等待”选项。对于未标记为异步的函数,可以定义一个名为await的变量,没有问题。

因此,异步不是函数签名的一部分,并且在生成的IL代码中没有语义。编译器必须严格知道如何正确编译该函数。它还指示编译器确保仅返回Task,Task <T>或void。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.