18

什么是关于区别的功能和意义任务FromResult VS TaskCompletionSource的setResult

TaskCompletionSource +的setResult VS任务+ FromResult

在SendAsync方法

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
{ 
    if (request.RequestUri.Scheme != Uri.UriSchemeHttps) 
    { 
     var response = new HttpResponseMessage(HttpStatusCode.Forbidden) {ReasonPhrase = "HTTPS Required"}; 
     var taskCompletionSource = new TaskCompletionSource<HttpResponseMessage>(); 
     taskCompletionSource.SetResult(response); 
     return taskCompletionSource.Task; 
    } 
    return base.SendAsync(request, cancellationToken); 
} 

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
{ 
    if (!request.RequestUri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)) 
    { 
     HttpResponseMessage reply = request.CreateErrorResponse(HttpStatusCode.BadRequest, "HTTPS is required for security reason."); 
     return Task.FromResult(reply); 
    } 

    return base.SendAsync(request, cancellationToken); 
} 

回答

28

Task.FromResult是.NET 4.5中的新增功能。它是创建TaskCompletionSource并调用SetResult的帮助器方法。如果您使用.NET 4或更早版本,则必须使用SetResult。

+0

你提到“.NET 4.5中的新增功能”使它成为我没有人提及的解决方案。 – Pascal

+2

'Task.FromResult'不使用TaskCompletionSource。 'Task.FromResult'调用_Special内部构造函数来创建一个已经完成的task_。 [源代码评论](http://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,11a386e7d7cae64a)。 – Fabio

+0

@Fabio谢谢澄清。我可能看到了一些来自MS的shim代码,它伪造了向后兼容的方法,并假定它是如何工作的。 –

3

如果你想要的是返回一个完成Task<TResult>与结果(或完成Task没有之一),只需使用Task.FromResult

Task.FromResult是一个简单的工具来创建一个完成的任务与结果。 TaskCompletionSource是一个更强大的工具,支持一切。您可以设置例外情况,返回未完成的任务并稍后设置结果等等

P.S:看起来您似乎在尝试通过返回完成的任务来“伪造”异步方法。尽管这是最好的方式,但确保“假装”异步真的是你想要完成的。

3

我相当确信Task.FromResult()在封面下做了非常类似的事情。

TaskCompletionSource的一个更好的用例场景是您自己实现多线程时。在这种情况下,您立即返回一个等待任务,其结果未设置,直到后台线程完成并调用TaskCompletionSource.SetResult()TaskCompletionSource.SetException()

1

我相信Task.FromResult()更有效,但你也可以做到以下几点,这是更具可读性,IMO:

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
{ 
    if (request.RequestUri.Scheme != Uri.UriSchemeHttps) 
     return new HttpResponseMessage(HttpStatusCode.Forbidden) {ReasonPhrase = "HTTPS Required"}; 
    return await base.SendAsync(request, cancellationToken); 
} 

,您仍然可以覆盖基本的虚拟SendAsync,因为async不改变方法签名。