22

功能和含义有什么区别

TaskCompletionSource + SetResult vs Task + 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);
}
4

5 回答 5

39

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

于 2014-01-21T12:21:19.737 回答
5

如果您只想返回Task<TResult>带有结果的已完成(或Task没有结果的已完成),只需使用Task.FromResult.

Task.FromResult是一个简单的工具,可以创建一个带有结果的已完成任务。TaskCompletionSource是一个更强大的工具,支持一切。您可以设置异常,返回未完成的任务并稍后设置它的结果等等

PS:您似乎正试图通过返回已完成的任务来“伪造”异步方法。尽管这是最好的方法,但请确保“伪造”异步确实是您想要完成的。

于 2014-01-21T11:22:39.820 回答
3

我相当肯定这Task.FromResult()在封面下做了非常相似的事情。

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

于 2014-01-21T11:30:25.290 回答
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);
}

您仍然可以覆盖基础的 virtual SendAsync,因为async不会更改方法签名。

于 2014-01-21T12:02:52.173 回答
0

Task.FromResult是为同步方法创建任务的便捷方法。尽管 Task 表示异步操作,但并非所有 Task 实际上都是异步的,并且可能只是同步方法的简单包装。

如果您使用 Task.FromResult,那么请在您的文档中说明您的方法不是“真正的”异步方法,而是语法糖块。这将通知调用者不要期望它的异步行为。

另一方面,如果您想手动创建异步函数,请按照此处所述使用 TaskCompletionSource 的SetResultTrySetResult方法。

无论您的 .NET 框架的版本如何,始终使用 TaskCompletionSource 而不是 Task.FromResult 来创建真正的异步函数。

资料来源:

  1. 任务.FromResult
  2. 任务的内部构造函数
  3. TaskCompletionSource.SetResult
  4. TaskCompletionSource.TrySetResult
于 2018-10-23T11:25:39.423 回答