Trying to only return task without async/await

    public async ValueTask<bool> AssetExistsForDeletion(int id, CancellationToken token)
    {
        return await fileDbContext.File.Where(x => x.Id == id
                        && x.ParentFileId == null
                        && x.IsDeleted == false)
                            .CountAsync(token) > 0 ? true : false;
    }

Can I somehow remove async/await from here while only returning task?

2 answers

  • answered 2021-04-14 18:15 Blindy

    await is nothing but syntactic sugar in the first place, so you can write the code explicitly yourself:

    public ValueTask<bool> AssetExistsForDeletion(int id, CancellationToken token)
    {
        return fileDbContext.File./* ... */CountAsync(token)
            .ContinueWith(t => t.Result > 0);
    }
    

    This will create and start the initial task as normal (your EF.Core query), then set up a continuation to return a result based on the result of the original task. Again, exactly the code await would generate.

  • answered 2021-04-14 18:50 Marc Gravell

    Honestly, I'd probably just use await here, but if you think that there is a good chance that the downstream operation will often complete synchronously (perhaps because of caching), you can indeed avoid the await- here generalized

    ValueTask<book> Foo()
    {
        ValueTask<int> pending = yourAwaitableQueryHere; // ... blah.CountAsync(...);
        return pending.IsCompletedSuccessfully
            ? new(pending.Result > 0) : Awaited(pending);
    
        static async ValueTask<bool> Awaited(ValueTask<int> pending)
            => (await pending) > 0;
    }
    

    This completely bypasses the async machinery in the synchronous success case, while still working properly with incomplete async operations and exceptions.

    You might also find that .Count(predicate) sometimes out-performs .Where(predicate).Count() (with or without async).