C #: Как преобразовать задачу <T []> в IEnumerable из задачи <T> - PullRequest
0 голосов
/ 05 мая 2019

У меня есть Nito.AsyncEx.AsyncCollection<MyItem[]>, который я хочу обернуть во что-то вроде IAsyncEnumerable<MyItem>.

На данный момент я использую IEnumerable<Task<T>> вместо IAsyncEnumerable.

И мне нужно что-то вроде SelectMany, чтобы сгладить список.И это проблема.Следующий код не работает.

Можно ли заставить его работать?

public static IEnumerable<Task<T>> Flatten<T>(IEnumerable<Task<T[]>> source) {
    foreach (Task<T[]> task in source) {
        // We should convert Task<T[]> to IEnumerable of Task<T>
        T[] result = await task;
        foreach (T item in result) {
            yield return Task.FromResult( item );
        }
    }
}

Ответы [ 2 ]

1 голос
/ 07 мая 2019

Лучшее решение - подождать несколько месяцев, пока IAsyncEnumerable<T> не станет реальностью.Следующее лучшее решение - использовать IAsyncEnumerable<T> из System.Interactive.Async .Но пока ...

IEnumerable<T> - итератор синхронного извлечения.Поэтому он должен предоставить свои T экземпляры синхронно.Более конкретно, для этого вопроса он должен предоставить count экземпляров синхронно.

Task<T> - асинхронное извлечение одного элемента.Он будет предоставлять только свой T экземпляр асинхронно.

Так вот в чем проблема: ваш желаемый результат IEnumerable<Task<T>> должен иметь возможность:

  1. Предоставлять каждый Task<T> синхронно.Не слишком сложно;Вы можете использовать TaskCompletionSource<T>, если это абсолютно необходимо.
  2. Обеспечить count синхронно.Другими словами, необходимо обеспечить каждые Task<T> синхронно.Все они.Это невозможно, учитывая ваш ввод.

Ваш ввод IEnumerable<Task<T[]>>.Поскольку это IEnumerable<>, вы можете получить счетчик синхронно, но это только количество элементов Task<T[]>, то есть количество элементов T[].Чтобы выполнить операцию сглаживания, вам потребуется await каждый из этих Task<T[]> элементов, чтобы получить количество T элементов.Таким образом, вы не можете создать IEnumerable<Task<T>>, который может синхронно знать, сколько у него предметов.

Вы сталкиваетесь с этим ограничением типа, потому что IEnumerable<Task<T>> равно , а не так же, как IAsyncEnumerable<T>.

Возможны следующие варианты:

  1. Используйте реальное IAsyncEnumerable<T>, написанное самостоятельно или через System.Interactive.Async.Плюсы: правильные типы допускают семантически точный код.Минусы: производство и потребление IAsyncEnumerable<T> по-прежнему является проблемой (пока).
  2. Выполните всю асинхронную работу заранее.Плюсы: проще код.Минусы: изменяет желаемую семантику.

При втором варианте ваш оператор сглаживания может выглядеть так:

public static async Task<IEnumerable<T>> Flatten<T>(IEnumerable<Task<T[]>> tasks) 
{
  var results = await Task.WhenAll(tasks);
  return results.SelectMany(x => x);
}

Пока у вас не будет истинного IAsyncEnumerable<T>, многие операторы будутпотребовать, чтобы будущее (Task<T>) закончилось снаружи вот так.

0 голосов
/ 05 мая 2019

Используйте вот так определите Task и определите в нем свой тип и дождитесь результата, убедитесь, что вы ожидаете асинхронного. как метод, приведенный ниже.

public async Task<IEnumerable<T>> getIEnumerable () {
 return await yourresult.toListAsync();

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...