Short question, and a short answer: ToListAsync - but why?
Let's check the code
ToListAsync is defined as:
public static async Task<List<TSource>> ToListAsync<TSource>(
this IQueryable<TSource> source,
CancellationToken cancellationToken = default)
{
var list = new List<TSource>();
await foreach (var element in source.AsAsyncEnumerable().WithCancellation(cancellationToken).ConfigureAwait(false))
{
list.Add(element);
}
return list;
}
And ToArrayAsync is defined as:
public static async Task<TSource[]> ToArrayAsync<TSource>(
this IQueryable<TSource> source,
CancellationToken cancellationToken = default)
=> (await source.ToListAsync(cancellationToken).ConfigureAwait(false)).ToArray();
So ToArrayAsync actually calls ToListAsync first, and then converts the resulting list to an array using ToArray(). So you get the overhead of creating a list, populating it, and then creating an array and copying the elements over.
This does not apply to ToHashSetAsync.