任务返回类型,带有和不使用异步



我对 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

  1. Task<TResult>,用于返回值的异步方法。
  2. Task,用于执行操作但没有返回值的异步方法。
  3. 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"。此关键字 允许在该方法中使用"等待"一词,并且可以使用 修改该方法如何处理其结果。就是这样。

该方法同步运行,直到找到"等待"一词,然后 单词是照顾异步的人。"等待"是运营商 接收参数:等待(异步操作) 以这种方式行为:

从这里

最新更新