Home > Back-end >  Await works on multiple lines, but not inline
Await works on multiple lines, but not inline

Time:10-09

I can get the following logic to work in 2 lines, but cannot pull it off inline:

var result = await BuildNewsCategories();
x.ListBuilder = () => result.Select(x => _mapper.Map<a, b>(x)).ToList();

My first attempt simply warns to add async:

x.ListBuilder = async () => await BuildNewsCategories()
   .Select(x => _mapper.Map<a, b>(x)).ToList();

But this is where I get stuck as now .Select is not found.

CodePudding user response:

x.ListBuilder is a synchronous delegate, so you cannot change this to a one-liner.

Not without blocking anyway which should be avoided.


Even if you were to block, for example:

x.ListBuilder = () => BuildNewsCategories()
   .Result
   .Select(x => _mapper.Map<a, b>(x))
   .ToList();

This would change the semantics of your code, because now BuildNewsCategories() is evaluated each time the delegate is invoked.

CodePudding user response:

TLDR: No, you cannot turn this into a usable one-liner since you have a synchronous delegate.

The rest of this answer provides extra information & potential solutions for other problems which may come up for when searching for this question.


Not having parentheses around await BuildNewsCategories() means that the compiler has no way of knowing:

  • Are you trying to do .Select on the Task<TResult? Or:
  • Are you trying to do .Select on the result of the Task (TResult)?

Without parentheses, it thinks you're attempting to call the LINQ .Select extension method on the Task returned & not the actual returned result (the "unwrapped" awaited result).

To do .Select on the result of the Task, surround await BuildNewsCategories() in parentheses:


If x.ListBuilder is of type List<T>:

x.ListBuilder = (await BuildNewsCategories())
                .Select(x => _mapper.Map<a, b>(x))
                .ToList()

If x.ListBuilder is of type Func<Task<List<T>>>:

x.ListBuilder = async () => (await BuildNewsCategories())
                            .Select(x => _mapper.Map<a, b>(x))
                            .ToList();

If x.ListBuilder is of type Func<List<T>>, your delegate is synchronous & you won't be able to get a one-liner without blocking on asynchronous code (defeating the purpose).

Your original solution would be the answer in this case:

var result = await BuildNewsCategories();
x.ListBuilder = () => result
                      .Select(x => _mapper.Map<a, b>(x))
                      .ToList();

CodePudding user response:

The other answers get the issue with the parentheses right, but do not return a delegate, but a list.

So this would be the correct code:

x.ListBuilder = async () => (await BuildNewsCategories())
             .Select(x => _mapper.Map<a, b>(x)).ToList();

This will work, if x.ListBuilder is of type Func<Task<List<b>>>, so it can be called as var list = await x.ListBuilder(). If it must be Func<List<b>>, it cannot be called asynchrounously and you have to move the await BuildNewsCategories() in a separate statement (your first snippet).

  • Related