【问题标题】:Why does this async method not have a compile error?为什么这个异步方法没有编译错误?
【发布时间】:2017-10-23 22:11:28
【问题描述】:

这可能是因为我对标记async的方法在编译过程中会发生什么缺乏了解,但是为什么这个方法会编译?

    public async Task<bool> Test()
    {
        return true;
    }

只是在这里寻找一个解释,所以我可以更好地理解发生了什么。 Task 会自动包装吗?为什么允许这种方法? (它不遵守方法签名,即返回一个Task&lt;bool&gt;)。

更新: 看来这也适用于以下参数:

    public void Main()
    {
        Input(Test);
    }

    public async Task<bool> Test()
    {
        return true;
    }

    public void Input(Func<Task<bool>> test)
    {

    }

其中,Test 方法隐式返回 Task

【问题讨论】:

  • How Async and Await works的可能重复
  • 您不需要在 async 方法中使用 await 某些东西。你问的是这个吗?
  • @RufusL 对,我明白这一点。但我不明白为什么方法 1 不必返回一个 Task (根据它的签名它应该)
  • Async return types 返回任务的结果,而不是任务本身。在您的示例中,async Task&lt;bool&gt; 返回bool
  • 你的问题有点混乱。假设您有async Task&lt;bool&gt; FooAsync() { await Whatever(); return true; },您还会问为什么要编译该方法吗?我想你可能不明白 async 方法中的 Task&lt;T&gt; returns 和 Treturn t; 表示在异步方法中使用此 T 完成任务,就像 return t; 表示在非异步代码中 使用 T 完成此方法

标签: c# async-await task task-parallel-library


【解决方案1】:

你可以看看你的代码的反编译版本here

using System;
public class C {
    public async System.Threading.Tasks.Task<bool> M() {
        return false;
    }
}

该方法被编译成一个普通的异步方法,使用状态机,它确实返回一个Task&lt;bool&gt;

public class C
{
    [CompilerGenerated]
    private sealed class <M>d__0 : IAsyncStateMachine
    {
        public int <>1__state;

        public AsyncTaskMethodBuilder<bool> <>t__builder;

        public C <>4__this;

        //called when you awaiting the Task
        void IAsyncStateMachine.MoveNext()
        {
            int num = this.<>1__state;
            bool result;
            try
            {
                result = false;  //the result is set
            }
            catch (Exception arg_0C_0)
            {
                Exception exception = arg_0C_0;
                this.<>1__state = -2;
                this.<>t__builder.SetException(exception);
                return;
            }
            this.<>1__state = -2;
            this.<>t__builder.SetResult(result); 
        }

        [DebuggerHidden]
        void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
        {
        }
    }

    [DebuggerStepThrough, AsyncStateMachine(typeof(C.<M>d__0))]
    public Task<bool> M()
    {
        // the state machine instance created
        C.<M>d__0 <M>d__ = new C.<M>d__0(); 
        <M>d__.<>4__this = this;
        <M>d__.<>t__builder = AsyncTaskMethodBuilder<bool>.Create();
        <M>d__.<>1__state = -1;
        AsyncTaskMethodBuilder<bool> <>t__builder = <M>d__.<>t__builder;
        <>t__builder.Start<C.<M>d__0>(ref <M>d__);
        return <M>d__.<>t__builder.Task;
    }
}

顺便说一句,编译器会给你一个警告,因为你从来没有在你的方法中await

警告 CS1998:此异步方法缺少“等待”运算符,将运行 同步。考虑使用 'await' 运算符来等待 非阻塞 API 调用,或 'await Task.Run(...)' 来做 CPU 密集型工作 在后台线程上。

你说得对,你可以只返回一个已完成的任务:

using System;
using System.Threading.Tasks;
public class C {
    public Task<bool> M() {
        return Task.FromResult(false); //no need to await here at all
    }

}

上述could be found here方法的其他编码方式。

using System;
using System.Threading.Tasks;
public class C {
    public async Task<bool> M() {
        return false;
    }

    public async Task<bool> M2(){
        return await Task.FromResult(false);
    }

    public Task<bool> M3(){
        return Task.FromResult(false);
    }
}

我希望这能为你澄清一些事情。

【讨论】:

  • 不确定我是否理解你。它确实返回了一个任务。查看反编译的代码。即使您执行return false;,实际状态机也会构建并返回任务。调用者可以在上面await,或者只是进一步存储/传递任务。
  • 所以,它只是通过添加 async 关键字隐式返回一个任务?如果我要返回 Task.Run(()=>true) 并删除 async 关键字,编译后的代码会有什么不同吗?
  • 请检查我回答中的最后一个链接。当您await 时,整个状态机人员都已构建并初始化。所有的性能/内存损失会不会:)如果你只是返回一个已完成的任务(Task.FromResult),这一切都不会发生。
  • 你也可以在那里玩Task.Run。你会发现它并没有什么不同,它只是 Task&lt;&gt; 对象的另一个工厂方法。
  • 是的,编译器会更改代码,以便在添加 async 关键字时返回 Task。这几乎是一个旧概念的语法糖。只需编写更少的代码。
猜你喜欢
  • 2012-04-20
  • 2012-02-08
  • 1970-01-01
  • 1970-01-01
  • 2015-10-30
  • 1970-01-01
  • 2021-01-15
  • 1970-01-01
  • 2018-12-11
相关资源
最近更新 更多