Asynchronous Iterator Task<Ienumerable<T>>

Asynchronous iterator TaskIEnumerableT

It sounds like what you may really be looking for is something like IObservable<T>, which is sort of like a push-based asynchronous IEnumerable<T>. See Reactive Extensions, a.k.a. Rx (code licensed under MIT) (no affiliation) for a huge host of methods that work with IObservable<T> to make it work like LINQ-to-Objects and more.

The problem with IEnumerable<T> is that there's nothing that really makes the enumeration itself asynchronous. If you don't want to add a dependency on Rx (which is really what makes IObservable<T> shine), this alternative might work for you:

public async Task<IEnumerable<char>> TestAsync(string testString)
{
return GetChars(testString);
}

private static IEnumerable<char> GetChars(string testString)
{
foreach (char c in testString.ToCharArray())
{
// do other work
yield return c;
}
}

though I'd like to point out that without knowing what's actually being done asynchronously, there may be a much better way to accomplish your goals. None of the code you posted will actually do anything asynchronously, and I don't really know if anything in // do other work is asynchronous (in which case, this isn't a solution to your underlying problem though it will make your code compile).

async TaskIEnumerableT throws is not an iterator interface type error

Only methods declaring that they return IEnumerable<T>, IEnumerable, IEnumerator or IEnumerator<T> can be implemented with iterator blocks. That rules out all async methods.

Fundamentally it's not clear how they'd work anyway, given that IEnumerable<T> is pull-based, whereas asynchronous methods are more reactive. Also, the point of an iterator block is that callers can see intermediate results - whereas the task returned from an async method will not complete until the async method itself has completed.

You'll need to go for an alternative approach - whether that's Rx or something else. You might want to think first not about what the implementation will look like, but what the caller will do. Perhaps you actually want an IEnumerable<Task<List<T>>?

Iterate TaskIEnumerableT in c#?

var fetchResult = await mapper.FetchAsync<User>(cql).ConfigureAwait(false);

fetchResult will be a IEnumerable<User> so it's up to you to iterate over the IEnumerable however you want to and print the underlying User objects with whatever method you prefer.

Console.WriteLine prints the result of the provided object's ToString() method and neither the returned IEnumerable object nor the contained User objects have the default implementation that you're looking for.

You can implement ToString() on the User class and do something like this:

Console.WriteLine(string.Join(Environment.NewLine, fetchResult));

Or you can just use a JSON library to convert the user object to a JSON string instead of overriding ToString():

Console.WriteLine(string.Join(
Environment.NewLine,
fetchResult.Select(user => JsonConvert.SerializeObject(user))))

[EDIT] you might be interested in our examples and docs:

https://www.datastax.com/examples (you can filter by C# language)

https://docs.datastax.com/en/developer/csharp-driver/3.14/features/components/mapper/

What's the difference between IAsyncEnumerableT and an iterator-generated IEnumerableTaskT?

wait for a sequence of numbers with a defined delay between each one

The delay happens at different times. IEnumerable<Task<T>> immediately returns the next element, which is then awaited. IAsyncEnumerable<T> awaits the next element.

IEnumerable<Task<T>> is a (synchronous) enumeration where each element is asynchronous. This is the proper type to use when you have a known number of actions to perform and then each item asynchronously arrives independently.

For example, this type is commonly used when sending out multiple REST requests simultaneously. The number of REST requests to make is known at the start, and each request is Selected into an asynchronous REST call. The resulting enumerable (or collection) is then usually passed to await Task.WhenAll to asynchronously wait for them all to complete.

IAsyncEnumerable<T> is an asynchronous enumeration; i.e., its MoveNext is actually an asynchronous MoveNextAsync. This is the proper type to use when you have an unknown number of items to iterate, and getting the next (or next batch) is (potentially) asynchronous.

For example, this type is commonly used when paging results from an API. In this case, you have no idea how many elements will eventually be returned. In fact, you may not even know if you are at the end until after retrieving the next page of results. So even determining whether there is a next item is an asynchronous operation.

Async/Await Iterate over returned TaskIEnumerableSomeClass

To iterate over the result of the Task, you need to get the result of the Task. And to do that, you should use await. This means you should change AddProjectDrawingAndComponentsFromServerToLocalDbAsync() into an async method:

private async Task AddProjectDrawingAndComponentsFromServerToLocalDbAsync(
CreateDbContext1 db, Project item)
{
var drawings = await client.GetDrawingsAsync(item.ProjectId);
foreach (var draw in drawings)
{
// whatever
}
db.SaveChanges();
}

This means that AddProjectDrawingAndComponentsFromServerToLocalDbAsync() (which is BTW quite a bad name for a method, I think) now returns a Task, so you should probably change the method that calls it into an async method too. This leads to “async all the way”, but that's unavoidable.

How to return async IEnumerablestring?

Try this:

public async Task<IEnumerable<string>> GetListDriversAsync()
{
var drives = await graphClient.Drive.Root.Children.Request().GetAsync();

IEnumerable<string> GetListDrivers()
{
foreach (var d in drives)
yield return d.ToString();
}

return GetListDrivers();
}

How to use Dapper Async method correctly & get data from TaskIEnumerableT

You are asserting on the Task which your Async() call returns, convert your test to async and "await" the call instead:

[Fact]
public async Task QueryMultipleAsyncTest()
{
//Arrange
string sqlCmd = "SELECT * FROM Emloyee";

//Act
IEnumerable<EmployeeDO> elist = await dbHelper.QueryAsync<EmployeeDO>(sqlCmd);

//Assert
Assert.True(elist != null);
}

Why am I not allowed to return an IAsyncEnumerable in a method returning an IAsyncEnumerable

This looks like a bug or at least an unintentional limitation, when reading the spec proposal.

The spec states that the presence of yield results in an iterator method; and the presence of both async and yield results in an asynchronous iterator method.

But I would like to understand why I cannot return an IAsyncEnumerable in my case.

The async keyword is making this into an asynchronous iterator method. Since you need the async for the await, then you'll need to use yield as well.

When writing "classic" IEnumerable methods, you can either return an IEnumerable or yield return several values. Why am I not allowed to do the same with IAsyncEnumerable?

With both IEnumerable<T> and IAsyncEnumerable<T>, you can perform synchronous work before returning the enumerable directly. In this case, the method is not special at all; it just does some work and then returns a value to its caller.

But you can't do asynchronous work before returning an asynchronous enumerator. In this case, you need the async keyword. Adding the async keyword forces the method to either be an asynchronous method or an asynchronous iterator method.

To put it another way, all methods can be classified into these different types in C#:

  • Normal methods. No async or yield present.
  • Iterator methods. A yield in the body without async. Must return IEnumerable<T> (or IEnumerator<T>).
  • Asynchronous methods. An async is present without yield. Must return a tasklike.
  • Asynchronous iterator methods. Both async and yield are present. Must return IAsyncEnumerable<T> (or IAsyncEnumerator<T>).

From yet another perspective, consider the state machine that must be used to implement such a method, and especially think about when the await GetRequiredThingAsync() code runs.

In the synchronous world without yield, GetRequiredThing() would run before returning the enumerable. In the synchronous world with yield, GetRequiredThing() would run when the first item of the enumerable is requested.

In the asynchronous world without yield, await GetRequiredThingAsync() would run before returning the async enumerable (and in that case, the return type would be Task<IAsyncEnumerable<T>>, since you have to do asynchronous work to get the async enumerable). In the asynchronous world with yield, await GetRequiredThingAsync() would run when the first item of the enumerable is requested.

Generally speaking, the only case when you want to do work before returning the enumerable is when you're doing precondition checks (which are synchronous by nature). Doing an API/DB call is not normal; most of the time the expected semantics are that any API/DB calls will be done as part of enumeration. In other words, even the synchronous code probably should have been using foreach and yield, just like the asynchronous code is forced to do.

On a side note, it would be nice in these scenarios to have a yield* for both synchronous and asynchronous iterators, but C# does not support that.



Related Topics



Leave a reply



Submit