Я ищу, чтобы создать функцию, которая принимает любую задачу, которая создает IEnumerable<T>
. Для иллюстрации рассмотрим следующую сигнатуру функции.
void DoWork<TElement>(Task<IEnumerable<TElement>> task)
{ }
Теперь я хотел бы назвать этот метод следующим образом:
Task<int[]> task = Task.FromResult(new[] { 1, 2, 3 });
DoWork(task);
Очевидно, что это не сработает, поскольку два типа Task
не совпадают, и что ковариация не существует для задач. Тем не менее, мне интересно, есть ли уловки, которые позволят этому работать, вдохновленные следующим примером.
async Task<IEnumerable<int>> GetTask()
{
return await Task.FromResult(new int[] { 1, 2, 3 });
}
Здесь await
эффективно создает новую задачу с результатом встроенной задачи, отсюда и иллюзия преобразования типов.
Чтобы дать более подробный пример, я бы хотел, чтобы пользователи вызывали DoWork
без чрезмерной нагрузки на конверсии:
// Service proxy method
Task<int[]> GetInts()
{
// simplified for brevity
return Task.FromResult(new[] { 1, 2, 3 });
}
// Service proxy method
Task<long[]> GetLongs()
{
// simplified for brevity
return Task.FromResult(new[] { 100L, 200L, 300L });
}
async Task<IEnumerable<T>> DoWork<T>(Func<Task<IEnumerable<T>>> getData,
Func<T, bool> predicate)
{
return (await getData()).Where(predicate);
}
// GOAL:
DoWork(GetInts, i => i % 2 == 0);
DoWork(GetLongs, l => l % 40 == 0);