2
\$\begingroup\$

I've written a lot of (await SomeTask).AsList(); in my project, and it's kind of annoying to keep wrapping it.

To fix this I've written a little extension method on Task<IEnumerable<T>> to be able to do this for me.

The code is like this:

/// <summary>
/// Awaits the Task and returns the result as Task as List<T>.
/// </summary>
/// <typeparam name="T">The type of the list.</typeparam>
/// <param name="task">The task to await.</param>
/// <returns>A task which returns as List which can be awaited.</returns>
public static async Task<List<T>> AsListAsync<T>(this Task<IEnumerable<T>> task)
{
    var result = await task;
    return result.AsList();
}

public static List<T> AsList<T>(this IEnumerable<T> enumerable)
{
    if (enumerable is List<T> list)
    {
        return list;
    }

    return new List<T>(enumerable);
}

This enables me to write this:

_someProperty = await SomeMethod().AsListAsync();

instead of:

_someProperty = (await SomeMethod()).AsList();

However I am not sure if this will introduce any unintended behavior or deadlocking. Can someone point out flaws in this code (if any)?

\$\endgroup\$
2
  • \$\begingroup\$ Why do you return Task<IEnumerable<T>> when you want Task<List<T>>? \$\endgroup\$
    – BCdotWEB
    Oct 19, 2022 at 20:33
  • \$\begingroup\$ What do you mean @BCdotWEB? I return a list. Some internal nuget package returns Task<IEnumerable<T>>, and I can't change the source of that package. That's why I have written this extension method. \$\endgroup\$
    – Joost00719
    Oct 21, 2022 at 5:49

2 Answers 2

3
\$\begingroup\$

Just two points to mention

  • you should add documentation to the second method as well, because it is a public method and you have documented the first method as well.
  • you should add a null check for the method parameters because one can call this methods directly as well, passing null.
\$\endgroup\$
2
\$\begingroup\$

I think you can implement the AsListAsync as a one-liner

public static async Task<List<T>> AsListAsync<T>(this Task<IEnumerable<T>> task)
    => await task is List<T> list ? list : new List<T>(task.Result);
\$\endgroup\$
5
  • \$\begingroup\$ Yes this should work, however the AsList() method is used throughout the project, My goal wasn't to make the extension as compact as possible, but to be easy to read/understand. \$\endgroup\$
    – Joost00719
    Oct 17, 2022 at 9:18
  • 1
    \$\begingroup\$ @Joost00719 Is it hard to read/understand? Is it too concise? \$\endgroup\$ Oct 17, 2022 at 9:27
  • \$\begingroup\$ No it's not very hard to understand, it's just a code style preference. I posted my code here to learn whether my code has any flaws, or if it's code which I can push to production without worrying about. \$\endgroup\$
    – Joost00719
    Oct 17, 2022 at 9:31
  • 1
    \$\begingroup\$ @Joost00719 I can only see two concerns 1) If the IEnumerable contains fairly large amount of data then AsList can be time consuming. 2) It might happen in the future that you have to support IAsyncEnumerable as well, where AsList might require you to do some external calls as well. \$\endgroup\$ Oct 17, 2022 at 9:56
  • 1
    \$\begingroup\$ @peter_Csla, thanks for the feedback! This wasn't something I thought of, and is good to know. Currently, I have no such case, so it isn't a problem for me (yet). I'll be putting a comment in the code that this is a possible issue if the dataset increases by a lot, or if the IEnumerable is IO bound. \$\endgroup\$
    – Joost00719
    Oct 17, 2022 at 10:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.