我的理解是,如果你有一个async
方法,其中唯一的await
是最终返回Task
,你可以删除async
和await
关键字,只返回Task
。
例如:
public async Task<object> Handle(object message)
{
var result = await Task.FromResult(message);
return result;
}
成为
public Task<object> Handle(object message)
{
return Task.FromResult(message);
}
但是,当该方法包含多个 await 语句时,这似乎不起作用。
例如:
async Task Main()
{
// outputs: Request
var requestHandlerAwaitingResult = (Request) await new HandlerAwaitingResult().Handle(new Request());
Debug.WriteLine(requestHandlerAwaitingResult.Description);
// InvalidCastException: Unable to cast object of type 'System.Threading.Tasks.Task`1[System.Object]' to type 'Request'.
var requestHandlerReturnTask = (Request) await new HandlerReturningTask().Handle(new Request());
Debug.WriteLine(requestHandlerReturnTask.Description);
}
public class Request
{
public string Description = "Request";
}
public class HandlerAwaitingResult
{
public async Task<object> Handle(object message)
{
await Task.Delay(TimeSpan.FromSeconds(1));
var result = await Task.FromResult(message);
return result;
}
}
public class HandlerReturningTask
{
public async Task<object> Handle(object message)
{
await Task.Delay(TimeSpan.FromSeconds(1));
return Task.FromResult(message);
}
}
谁能告诉我为什么这不起作用?
从根本上说,两者之间有什么区别
public class HandlerReturningTask
{
public async Task<object> Handle(object message)
{
await Task.Delay(TimeSpan.FromSeconds(1));
return Task.FromResult(message);
}
}
和
public class HandlerReturningTask
{
public async Task<object> Handle(object message)
{
await Task.Delay(TimeSpan.FromSeconds(1));
return await Task.FromResult(message);
}
}
和
public class HandlerReturningTask
{
public Task<object> Handle(object message)
{
return Task.FromResult(message);
}
}
我仍然不确定我是否理解这个问题。但根据您的编辑:
从根本上说,[...
。return Task.FromResult(message);
...]和[...return await Task.FromResult(message);
...]之间有什么区别
了解await
的作用很重要:它表示方法中的一个点,该方法可以返回,然后当"可等待"(例如Task
)完成时,该方法中的执行可以恢复。
如果Task
是Task<T>
,那么await
要做的另一件事是在方法中恢复执行时,解开Task<T>
对象的T
值,即获取其Result
属性值。await
表达式的计算结果为该值。
最后,对于async Task<T>
方法,return
语句会导致方法返回的Task<T>
对象(在第一个await
表达式处)在return {value}
表达式中具有Result
值。
因此,在您的示例中,return Task.FromResult(message);
会导致 Task<object>.Result
属性具有类型为 Task<Request>
的对象的值。稍后,await
表达式计算此对象的Result
属性值,并尝试将其强制转换为类型 Request
的对象,这当然是非法的。
使用 return await Task.FromResult(message);
会导致首先计算await
表达式(因此 return
语句可以返回该表达式的结果),这具有获取 Task<Request>.Result
属性值的效果。然后,return
语句返回此值,使等待的Task<object>.Result
值成为最初传递给该方法Request
对象。当然,当调用者中的await
解开包装时,这可以转换回类型 Request
。
也就是说,通常你只会直接返回值。将其包装在 Task<T>
对象中,然后立即用await
表达式将其解开包装是没有意义的。在这种情况下编写return message;
将具有完全相同的结果,但代码更具可读性和效率。
生成的状态机处理任何可等待的状态机。不仅是任务。
如果只处理一项任务,则可以绕过计算机生成的状态机的开销。但是,在出现异常的情况下,堆栈跟踪将不是您所期望的。
异步方法的返回类型将始终是要返回的任何内容的任务。