我对
async
关键字的行为有点困惑。
假设我有两种方法,
public async Task DoSomething1()
{
await Task.Run(() =>
{
for(int i = 0; i<3; i++)
{
Console.WriteLine("I m doing something:" + i);
}
});
}
还有
public Task DoSomething2()
{
return Task.Run(() =>
{
for(int i = 0; i<3; i++)
{
Console.WriteLine("I m doing something:" + i);
}
});
}
据我了解,这两种方法都是值得期待的。但是,当我编写一个具有
Task
返回类型但没有 async
关键字的方法时,我需要返回 Task
,否则编译器会生成错误。方法应该返回其类型,这是很常见的事情。但是当我将它与 async
关键字一起使用时,编译器会生成另一个错误,您无法返回 Task
。那么这意味着什么呢?我在这里完全困惑了。
如果您在代码中使用
await
,则需要在方法中使用 async
关键字。
如果您使用
async
并希望返回实际类型,您可以声明您的方法将该类型返回为通用任务,如下所示 Task<int>
。
以下是
async
方法的有效返回类型:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/async-return-types
Task<TResult>
,用于返回值的异步方法。Task
,用于执行操作但不返回任何值的异步方法。void
,用于事件处理程序。TL;DR - 返回类型自动包装在任务中。
我对此投了反对票,所以我更详细地重新阅读了这个问题并找到了问题的根源。这与方法签名中的返回类型无关。它是关于返回值值;为什么我不需要返回显式的
Task
类型? (而且这不是重复的问题!)
不管怎样,我们来看看这个方法:
public Task TaskMethod()
{
return Task.CompletedTask;
}
这看起来很正常,也是我们在 C# 中所习惯的。您声明返回类型并返回该类型的对象。简单的。 (事实上,“降低”的代码是完全相同的。)
现在介绍异步情况。
public async Task MethodAsync()
{
return Task.CompletedTask;
}
这会生成编译错误:
error CS1997: Since 'C.MethodAsync()' is an async method that returns 'Task', a return keyword must not be followed by an object expression. Did you intend to return 'Task<T>'?
好吧,那我们就不能直接返回任务了,我们来做正确的事情吧。如果我们返回一些东西,就更容易看到这个例子,所以让我们返回 int。
public async Task<int> MethodAsync()
{
return 1;
}
(此方法会发出警告,表明我们正在使用异步而不等待,但现在忽略它。)
降低的代码复杂,但是可以看到会生成一个状态机。 MethodAsync 看起来像这样:
[CompilerGenerated]
private sealed class <MethodAsync>d__0 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder<int> <>t__builder;
public C <>4__this;
private void MoveNext()
{
int num = <>1__state;
int result;
try
{
result = 1;
}
catch (Exception exception)
{
<>1__state = -2;
<>t__builder.SetException(exception);
return;
}
<>1__state = -2;
<>t__builder.SetResult(result);
}
void IAsyncStateMachine.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
this.MoveNext();
}
[DebuggerHidden]
private void SetStateMachine(IAsyncStateMachine stateMachine)
{
}
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
this.SetStateMachine(stateMachine);
}
}
[AsyncStateMachine(typeof(<MethodAsync>d__0))]
[DebuggerStepThrough]
public Task<int> MethodAsync()
{
<MethodAsync>d__0 stateMachine = new <MethodAsync>d__0();
stateMachine.<>t__builder = AsyncTaskMethodBuilder<int>.Create();
stateMachine.<>4__this = this;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
并且可以看到这里的Task是在public方法中自动返回的。状态机实现方法体。
您可以看到返回的实际值是包装在任务中的
<>t__builder
的 int。
要亲自查看降低的代码,您可以在https://sharplab.io中尝试。
写完所有这些之后,我找到了另一个答案,以不同的方式解释了它。猜猜这个答案是谁写的? https://stackoverflow.com/a/37647093/1804678
(...)“异步”。这个关键词 允许在方法内部使用“await”一词,并且 修改方法处理其结果的方式。就是这样。
该方法同步运行,直到找到单词“await”并且该 word 是负责异步的。 “Await”是一个运算符 接收参数:可等待(异步操作) 行为方式如下:
从这里