C# 为什么我的TCS没有等待?

C# 为什么我的TCS没有等待?,c#,.net,async-await,task-parallel-library,taskcompletionsource,C#,.net,Async Await,Task Parallel Library,Taskcompletionsource,async关键字确实会导致更改(即使方法中没有wait),但它主要是允许出现wait 但我没想到会发生以下情况: static void Main(string[] args) { Task t = Go(); t.Wait(); } static async Task Go() { Console.WriteLine(1); await AAA(3000); Console.WriteLine(2); } static Task<objec

async
关键字确实会导致更改(即使方法中没有wait),但它主要是允许出现
wait

但我没想到会发生以下情况:

static void Main(string[] args)
{
    Task t = Go();
    t.Wait();
}

static async Task Go()
{
    Console.WriteLine(1);
    await AAA(3000);
    Console.WriteLine(2);
}


static  Task<object> AAA(int a) // <--- No `async`
{
    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
    Task.Delay(a).ContinueWith(b => tcs.SetResult(null));
    return tcs.Task;
}
但如果我改变

static  Task<object> AAA(int a) 
问题


为什么我看不到延误?TCS仅在三秒后才得到解决。同时,任务未被解决,应该等待。

因为当您从异步方法返回
任务时,返回类型为
任务
时,您得到的
任务
与您的任务(您期望等待的)在一起。这就是你应该做的:

static async Task<object> AAA(int a)
{
  await Task.Delay(a);
  return null;
}
静态异步任务AAA(int a)
{
等待任务。延迟(a);
返回null;
}

简而言之,尽量避免将异步等待和直接任务操作混用在一种方法中。

如果没有
async
关键字,您将从
AAA
返回
TaskCompletionSource
的任务,并等待它完成(这将在延迟完成后发生)

但是,当添加
async
关键字时,该方法返回的任务是同步完成的状态机任务。该任务中(因此)有
TaskCompletionSource
的任务,但这不是您正在等待的任务

如果希望该方法等待
任务完成源
的任务,则可以等待
任务
的内部任务:

或者等待
TaskCompletionSource
,而不是返回它:

async Task AAA(int a)
{
    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
    Task.Delay(a).ContinueWith(b => tcs.SetResult(null));
    await tcs.Task;
}

正如Serg所提到的,在Visual Studio中查看此示例:

        static async Task<int> AAA(int a) // <--- No `async`
        {
             TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
             Task.Delay(a).ContinueWith(b =>
             {
                  tcs.SetResult(1);
             });
             return tcs.Task;
        }
静态异步任务AAA(int a)//
{
tcs.SetResult(1);
});
返回tcs.Task;
}
您将得到如下错误:


由于这是一个异步方法,返回表达式的类型必须是“int”而不是“Task”,因为您的方法将同步运行。这就是为什么需要返回
int
,而不是
Task

关于您的最后一句话,该方法将以Wynchronous方式运行,并且它确实需要返回
int
而不是
Task
,但该方法同步运行并不是他必须返回
int
的原因。他需要返回一个
int
,因为所有
async
方法都将返回的值包装在
任务中。这个方法将同步运行是正确的,但这并不是错误的原因。razor118,这个答案将非常棒,因为注释-使用一些强类型而不是
对象
,会使错误变得非常明显。或者您可以通过应用@Servy的注释来清理它。据我所知,Serv async关键字负责通知编译器构建状态机。它不会将返回类型包装到任务。看看私有静态void Test(){}和私有静态异步void TestAsync(){}@razor118
async
的IL代码,它没有包装返回类型(这就是为什么它仍然是
Task
),但它包装了返回(这就是为什么必须返回
int
)我认为答案是问题的最好证明-将
静态任务AAA(inta)
更改为
静态任务AAA(inta)
(对代码进行必要的更改),然后添加
异步
。是的,我被as T咬了一口。现在想想看-这是一个愚蠢的问题。每个异步方法返回的结果都是由任务包装的。所以这里我实际上返回了
任务
愚蠢与否,这是你的要求,但绝对是教育性的(而且写得很好)。这两个版本的代码(异步/非异步)看起来似乎都是合理的,让我感到困惑(我敢打赌,基于投票的人已经够多了)。@AlexeiLevenkov谢谢:-)
static async Task<object> AAA(int a)
{
  await Task.Delay(a);
  return null;
}
await ((Task) await AAA(3000));
async Task AAA(int a)
{
    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
    Task.Delay(a).ContinueWith(b => tcs.SetResult(null));
    await tcs.Task;
}
async Task<object> AAA(int a)
{
    await Task.Delay(a);
    return null;
}
        static async Task<int> AAA(int a) // <--- No `async`
        {
             TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
             Task.Delay(a).ContinueWith(b =>
             {
                  tcs.SetResult(1);
             });
             return tcs.Task;
        }