我一直认为,如果一个方法应该返回一个值,那么如果方法主体不返回一个值,程序就不会编译。对于带有异步关键字的方法,情况并非如此。我认为异步关键字允许身体中的方法有一个等待表达式。但是它也允许方法的主体在返回值上吐口水。
我是否正确地理解带有异步关键字的方法是关于强制返回值的规则的一个例外?
Task MyMethod1() //Error CS0161 'MyMethod1()': not all code paths return a value
{
}
async Task MyMethod2() //Do not care
{
}
发布于 2022-08-24 18:17:57
你说得对,这是个例外。void
和async Task
方法都具有有效的void
返回类型,并且不需要return
语句。这是在语言规范中指定的
(强调地雷)
如果返回类型为
void
,或者方法为async
,返回类型为System.Threading.Tasks.Task
,则方法的有效返回类型为System.Threading.Tasks.Task
。否则,非异步方法的有效返回类型是其返回类型,具有返回类型的async
方法的有效返回类型为T
。 如果方法的有效返回类型为void
,且该方法具有块体,则块中的返回语句(§12.10.5)不应指定表达式。如果void方法块的执行正常完成(即控制流从方法主体的末尾流出),则该方法只返回其调用方.。 当方法的有效返回类型不是无效且该方法有块体时,该方法正文中的每个返回语句都应指定一个隐式可转换为有效返回类型的表达式。不能访问值返回方法的方法主体的端点。
然后直觉地思考,即使他们想要设计它,以便您必须返回Task
的一个实例,您会返回什么Task
?没有什么是有意义的返回!异步方法返回的任务应该表示它执行的异步操作。
实际上,一些编译器神奇地将方法体中的代码转换为Task
,并使您的方法返回该代码。另见:异步在C#中是如何工作的?
发布于 2022-08-24 18:52:22
async
/ await
关键字在C#编译器中触发了大量魔术。以“简单”为例;
async Task MyMethod2()
{
Console.WriteLine("Before");
await Task.Delay(1000);
Console.WriteLine("After");
}
编译器的目标是重写您的方法,这样它就可以在每个await
上暂停,然后再继续。它将方法移动到新类型,使用实例字段跟踪方法暂停的位置,以及任何局部变量的值。这样你就可以假装你的方法更接近了;
void MyMethod2()
{
Console.WriteLine("Before");
var task = Task.Delay(1000);
if (!task.IsCompleted) {
... pause / resume magic ...
}
Console.WriteLine("After");
}
您可以通过反编译器看到所有血淋淋的细节。
发布于 2022-08-24 18:54:05
不不例外。可以捕获返回的Task
对象并将其用作任何其他返回值。
async Task F1Async()
{
await Task.Delay(TimeSpan.FromMilliseconds(200));
}
async Task F2Async()
{
Task t1 = F1Async();
// Do other things if you wish here.
await t1;
}
https://stackoverflow.com/questions/73481176
复制