我对 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/programpramming-guide/concepts/async/async/async-return-types
-
Task<TResult>
,用于返回值的异步方法。 -
Task
,用于执行操作但没有返回值的异步方法。 -
void
,用于事件处理程序。
2022年8月的新答案
tl; dr-返回类型自动包裹在任务中。
我对此进行了低估,因此我更详细地重新阅读了问题,并扎根了。这与该方法的签名中的返回类型无关。它关于返回 value 。这也不是重复的问题!
无论如何,让我们看一下此方法:
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;
}
您可以在此处看到任务在公共方法中自动返回。状态机实现方法主体。
您可以看到返回的实际值是任务包裹的<>t__builder
的INT。
要自己查看降低的代码,您可以在https://sharplab.io。
中尝试一下也写了所有这些内容后,我找到了另一个答案,以不同的方式解释它。猜猜谁写了这个答案?https://stackoverflow.com/a/37647093/1804678
(...)" async"。此关键字 允许在该方法中使用"等待"一词,并且可以使用 修改该方法如何处理其结果。就是这样。
该方法同步运行,直到找到"等待"一词,然后 单词是照顾异步的人。"等待"是运营商 接收参数:等待(异步操作) 以这种方式行为:
从这里