Сквозная передача для IAsyncEnumerable? - PullRequest
4 голосов
/ 23 января 2020

Я хотел бы знать, есть ли способ написать функцию, которая "пропустит" IAsyncEnumerable ... то есть функция вызовет другую функцию IAsyncEnumerable и выдаст все результаты без необходимости писать foreach чтобы сделать это?

Я часто пишу этот шаблон кода. Вот пример:

async IAsyncEnumerable<string> MyStringEnumerator();

async IAsyncEnumerable<string> MyFunction()
{
   // ...do some code...

   // Return all elements of the whole stream from the enumerator
   await foreach(var s in MyStringEnumerator())
   {
      yield return s;
   }
}

По какой-либо причине (из-за многоуровневого дизайна) моя функция MyFunction хочет вызвать MyStringEnumerator, но затем просто выдает все без вмешательства. Я должен продолжать писать эти foreach циклы, чтобы сделать это. Если бы это был IEnumerable, я бы вернул IEnumerable. Если бы это был C ++, я мог бы написать макрос, чтобы сделать это.

Какая лучшая практика?

Ответы [ 3 ]

4 голосов
/ 23 января 2020

Если бы это был IEnumerable, я бы возвратил IEnumerable.

Ну, вы можете просто сделать то же самое с IAsyncEnumerable (обратите внимание, что async удален):

IAsyncEnumerable<string> MyFunction()
{
 // ...do some code...

 // Return all elements of the whole stream from the enumerator
 return MyStringEnumerator();
}

Тем не менее, здесь есть важный смысл c. При вызове метода перечислителя ...do some code... будет выполняться немедленно , а не при перечислении перечислителя.

// (calling code)
var enumerator = MyFunction(); // `...do some code...` is executed here
...
await foreach (var s in enumerator) // it's not executed here when getting the first `s`
  ...

Это верно для обоих синхронных и асинхронные перечислимые числа.

Если вы хотите, чтобы ...do some code... выполнялся при перечислении перечислителя, тогда вам нужно будет использовать foreach / yield l oop, чтобы получить семантику отложенного выполнения :

async IAsyncEnumerable<string> MyFunction()
{
 // ...do some code...

 // Return all elements of the whole stream from the enumerator
 await foreach(var s in MyStringEnumerator())
   yield return s;
}

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

IEnumerable<string> ImmediateExecution()
{
 // ...do some code...

 // Return all elements of the whole stream from the enumerator
 return MyStringEnumerator();
}

IEnumerable<string> DeferredExecution()
{
 // ...do some code...

 // Return all elements of the whole stream from the enumerator
 foreach(var s in MyStringEnumerator())
   yield return s;
}
1 голос
/ 05 марта 2020

Возврат Task<IAsyncEnumerable<Obj>> из вызывающего метода, похоже, работает

async IAsyncEnumerable<string> MyStringEnumerator();

async Task<IAsyncEnumerable<string>> MyFunction()
{
    await Something();

    return MyStringEnumerator();
}

Затем вам нужно дождаться MyFunction (). Так что использовать в асин * foreach c будет

await foreach (string s in await MyFunction()) {}
0 голосов
/ 26 января 2020

Я просто возвращаю IAsyncEnumerable, полученный другим способом. Это работает. Нет необходимости в другом asyn c foreach с возвращаемым доходом. Попробуйте это.

...