Await或Task.FromResult

lab*_*roo 20 .net c# task-parallel-library async-await

我有一个服务可以说,

public interface ISomeService
{
    Task<bool> DoSomeExpensiveCheckAsync(string parameter);
}
Run Code Online (Sandbox Code Playgroud)

我有这个课程来消费服务.它只需要做一些简单的空检查,然后返回服务响应.

public class SomeServiceConsumer
{
    private readonly ISomeService _serviceClient;

    public SomeServiceConsumer(ISomeService serviceClient)
    {
        _serviceClient = serviceClient;
    }

    public async Task<bool> DoSomething1Async(string someParameter)
    {
        if (string.IsNullOrWhiteSpace(someParameter))
        {
            return false;
        }
        return await _serviceClient.DoSomeExpensiveCheckAsync(someParameter);
    }

    //No async or await keywords   
    public Task<bool> DoSomething2Async(string someParameter)
    {
        if (string.IsNullOrWhiteSpace(someParameter))
        {
            return Task.FromResult(false);
        }
        return _serviceClient.DoSomeExpensiveCheckAsync(someParameter);
    }
}
Run Code Online (Sandbox Code Playgroud)

我应该做的DoSomething1Async还是DoSomething2Async

根据这个答案,我不应该用不必要的东西包裹await但是我必须Task.FromResult(false)用于短路DoSomething2Async

但根据这个答案,有一些案例try/catchusing陈述,我实际上应该await在返回之前.

我当时说的是正确的

  1. 如果我必须使用try/catchusing我应该await

  2. await如果你只是要返回,否则不要.并Task.FromResult用于短路

DoSomething1Async更喜欢,如果有人说这无关紧要,我想在任何地方都这样做.

Cor*_*son 17

如果你担心它,请缓存Task:

static readonly Task<bool> falseTask = Task.FromResult(false);
Run Code Online (Sandbox Code Playgroud)

async关键字还会在返回的内容中包含异常Task以及正确的堆栈跟踪.这是权衡行为的安全性.

让我们看看每种情况会有所不同的差异情景:

async Task UseSomething1Async(string someParameter)
{
    // if IsNullOrWhiteSpace throws an exception, it will be wrapped in
    // the task and not thrown here.
    Task t1 = DoSomething1Async(someParameter);

    // rather, it'll get thrown here. this is best practice,
    // it's what users of Task-returning methods expect.
    await t1;

    // if IsNullOrWhiteSpace throws an exception, it will
    // be thrown here. users will not expect this.
    Task t2 = DoSomething2Async(someParameter);

    // this would never have been reached.
    await t2;
}
Run Code Online (Sandbox Code Playgroud)

只是在这里说明一点 - IsNullOrWhiteSpace实际上并没有因任何原因抛出任何异常.

就堆栈跟踪而言,异步堆栈跟踪由您所在的位置决定await.No await表示该方法将从堆栈跟踪中消失.

Say DoSomeExpensiveCheckAsync抛出异常.在这种情况下DoSomething1Async,堆栈跟踪看起来像caller -> DoSomething1Async -> DoSomeExpensiveCheckAsync.

在这种情况下DoSomething2Async,堆栈跟踪看起来像caller -> DoSomeExpensiveCheckAsync.根据代码的复杂程度,这可能会使调试变得困难.

在实践中,我通常只会直接返回一个Task如果我知道在它之前不会抛出异常,并且如果方法名称仅仅是转发到另一个重载的过载.这条规则总有例外,你必须要有最大化性能的地方.只需仔细挑选,即可意识到您可能会让您和您的用户的生活更加艰难.