Léster
Léster

Reputation: 1279

Continuation of asynchronous method in an extension method

I'm tired of having to do this in my views any time I need to populate a <select> element:

//ListObjectsFromDbAsync returns a List<T>
var data = await _manager.ListObjectsFromDbAsync();
var items = data
    .Select(d=>new SelectListItem { /* conversion to SelectListItem here */})
    .ToArray();

The problem is, ListObjectsFromDbAsync() obviously requires to be awaited in order to work with the list items.

So I devised this extension method:

public static class Extensions
{
    public static Task<SelectListItem[]> AsSelect<T>(this Task<List<T>> src, Func<T, string> text, Func<T, string> value, Func<T, bool> selected = null)
    {
        if (src == null)
        {
            throw new NullReferenceException();
        }
        if (text == null)
        {
            throw new ArgumentNullException(nameof(text));
        }
        if (value == null)
        {
            throw new ArgumentNullException(nameof(value));
        }
        var result = src.ContinueWith(s =>
        {
            var count = s.Result.Count;
            var output = new SelectListItem[count];
            for (int i = 0; i < count; i++)
            {
                var e = s.Result[i];
                var d = new SelectListItem
                {
                    Text = text(e),
                    Value = value(e),
                    Selected = selected != null && selected(e)
                };
                output[i] = d;
            }
            return output;
        });
        return result;
    }
}

and now I can do this:

var items = await _manager
    .ListObjectsFromDbAsync()
    .AsSelect(a => a.Name, a => a.Id.ToString());

which, in my opinion, is simpler and cleaner.

Synthetic tests show that it works, but what I'm concerned about is using Task objects in an ASP.NET Core MVC application (I've heard it's not a really good idea; also I think what I did is a classical fake async method and I don't know what bad side effects this would have). Is there any downside or condition I should be worried about?

Upvotes: 0

Views: 699

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456857

what I'm concerned about is using Task objects in an ASP.NET Core MVC application (I've heard it's not a really good idea; also I think what I did is a classical fake async method and I don't know what bad side effects this would have).

This is not a fake async method; there's no Task.Factory.StartNew or Task.Run anywhere. So this should be fine for ASP.NET.

Is there any downside or condition I should be worried about?

Yes. ContinueWith is problematic; it's a low-level method with dangerous default behavior. Instead of using ContinueWith, just use await inside your extension method; that will make the code both more correct and clearer:

public static class Extensions
{
  public static async Task<SelectListItem[]> AsSelectAsync<T>(this Task<List<T>> src, Func<T, string> text, Func<T, string> value, Func<T, bool> selected = null)
  {
    ... // null checks
    var data = await src;
    return data.Select(d => new SelectListItem
    {
      Text = text(e),
      Value = value(e),
      Selected = selected != null && selected(e)
    }).ToArray();
  }
}

Upvotes: 3

Related Questions