[英]Why does the C# compiler handle empty async Task methods different to just return Task.CompletedTask?
Hello,你好,
Edit: the post was edited to not use empty methods to be more clear about what I want to know.编辑:该帖子被编辑为不使用空方法以更清楚地了解我想知道的内容。
Is there a reason why the C# compile does not compile a async Task
method without using await
to return Task.CompletedTask
? C# 编译不使用await
返回Task.CompletedTask
的情况下不编译async Task
方法是否有原因?
Sometimes it is necessary to implement a method that returns a Task
but it is not using await
.有时有必要实现一个返回Task
但没有使用await
的方法。
I am wondering if there is a reason why the generated IL code is so different between that two methods:我想知道生成的 IL 代码在这两种方法之间是否存在如此不同的原因:
public async Task DoNothing()
{
Console.WriteLine("nothing");
}
public Task DoNothing()
{
Console.WriteLine("nothing");
return Task.CompletedTask;
}
I created two Fiddles where the generated IL code can be viewed.我创建了两个 Fiddles,可以在其中查看生成的 IL 代码。
async Task
: https://dotnetfiddle.net/UQuJUh async Task
: https://dotnetfiddle.net/UQuJUh
Task.CompletedTask
: https://dotnetfiddle.net/eRr4i1 Task.CompletedTask
: https://dotnetfiddle.net/eRr4i1
So is there a reason why the compiler does not optimize the code to handle both cases the same way?那么编译器不优化代码以以相同方式处理这两种情况的原因是什么? Thank you.谢谢你。
There is a significant difference in the way exceptions are handled in those two pieces of code, which are therefore not equivalent :在这两段代码中处理异常的方式存在显着差异,因此它们是不等价的:
public async Task DoNothing()
{
Console.WriteLine("nothing");
}
In the case that Console.WriteLine
raised an exception, the exception is actually internally caught and stored inside the resulting Task
, indicated by Task.IsFaulted
.在Console.WriteLine
引发异常的情况下,异常实际上是在内部捕获并存储在结果Task
中,由Task.IsFaulted
指示。 The exception is only actually "thrown" when you use await
on the task.只有当您在任务上使用await
时,才会真正“抛出”异常。
public Task DoNothing()
{
Console.WriteLine("nothing");
return Task.CompletedTask;
}
This case however is fully synchronous;然而,这种情况是完全同步的; the potential exception from Console.WriteLine
would be raised even before any task could be returned or processed.来自Console.WriteLine
的潜在异常甚至在任何任务可以被返回或处理之前就会被引发。 I'd argue this is actually a bit less safe than the first option, since this behaviour might be unexpected.我认为这实际上比第一个选项更不安全,因为这种行为可能是出乎意料的。 Iterators show similar behaviour for the difference between yield break;
迭代器对yield break;
and return Array.Empty<object>();
并return Array.Empty<object>();
. .
Now your question originally asked about an actually empty method.现在您的问题最初询问了一个实际上是空的方法。 Well, it could be the case that the method is not actually empty;好吧,可能是该方法实际上不是空的; it may contain breakpoints in debug mode, injected code or perhaps auto-generated checks for the arguments, in the future.将来它可能包含调试模式下的断点、注入代码或可能为 arguments 自动生成的检查。 Even the empty try
block is still generated for an empty method body:即使是空的方法体,仍然会生成空的try
块:
.try
{
IL_0000: leave.s IL_0019
} // end .try
catch [mscorlib]System.Exception
{
Now I can imagine an exception in generating async
method could be added to the compiler for the case of a truly empty method, but it would only complicate the code, for no (arguably) real gain.现在我可以想象,对于真正空的方法,可以将生成async
方法的异常添加到编译器中,但这只会使代码复杂化,而没有(可以说)真正的收益。 There might be a point of having an empty async
method (such as to give other programmers who might want to implement it in a future a hint), but then you don't need to care about performance that much to warrant such an optimization (and you have a trivial solution anyway).可能会有一个空的async
方法(例如给其他可能想要在未来实现它的程序员一个提示),但是你不需要那么关心性能来保证这样的优化(无论如何你都有一个简单的解决方案)。
(Interesting side note: C# 11 might introduce automatic raising of ArgumentNullException
from parameters marked with !!
. At this time, the exception is actually raised outside of the async
/iterator method's code, immediately after the call, so it could be argued that the method body, or what becomes of it, is still, technically, empty.) (有趣的旁注:C# 11 可能会从标有!!
的参数中引入ArgumentNullException
的自动引发。此时,异常实际上是在async
/iterator 方法的代码之外,在调用之后立即引发的,因此可以说方法体,或者它的结果,在技术上仍然是空的。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.