I have an interface which is written like this:
public interface IItemRetriever
{
public IAsyncEnumerable<string> GetItemsAsync();
}
I want to write an empty implementation that returns no item, like so:
public class EmptyItemRetriever : IItemRetriever
{
public IAsyncEnumerable<string> GetItemsAsync()
{
// What do I put here if nothing is to be done?
}
}
If it was a plain IEnumerable, I would return Enumerable.Empty<string>();
, but I didn't find any AsyncEnumerable.Empty<string>()
.
I found this which works but is quite weird:
public async IAsyncEnumerable<string> GetItemsAsync()
{
await Task.CompletedTask;
yield break;
}
Any idea?
If you install the System.Linq.Async
package, you should be able to use AsyncEnumable.Empty<string>()
. Here's a complete example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
IAsyncEnumerable<string> empty = AsyncEnumerable.Empty<string>();
var count = await empty.CountAsync();
Console.WriteLine(count); // Prints 0
}
}
If for any reason you don't want to install the package which is mentioned in Jon's answer, you can create the method AsyncEnumerable.Empty<T>()
like this:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public static class AsyncEnumerable
{
public static IAsyncEnumerator<T> Empty<T>() => EmptyAsyncEnumerator<T>.Instance;
class EmptyAsyncEnumerator<T> : IAsyncEnumerator<T>
{
public static readonly EmptyAsyncEnumerator<T> Instance =
new EmptyAsyncEnumerator<T>();
public T Current => default!;
public ValueTask DisposeAsync() => default;
public ValueTask<bool> MoveNextAsync() => new ValueTask<bool>(false);
}
}
Note: The answer doesn't discourage using the System.Linq.Async
package. This answer provides a brief implementation of AsyncEnumerable.Empty<T>()
for cases that you need it and you cannot/don't want to use the package. You can find the implementation used in the package here.
I wanted to avoid installing System.Linq.Async
(due to its issues with namespace collisions) but the previous answer does not actually implement IAsyncEnumerable<T>
as requested in the original question. Here's a full solution which implements that interface to easily allow calling AsyncEnumerable.Empty<T>
in the same way that Enumerable.Empty<T>
works today.
public static class AsyncEnumerable
{
/// <summary>
/// Creates an <see cref="IAsyncEnumerable{T}"/> which yields no results, similar to <see cref="Enumerable.Empty{TResult}"/>.
/// </summary>
public static IAsyncEnumerable<T> Empty<T>() => EmptyAsyncEnumerator<T>.Instance;
private class EmptyAsyncEnumerator<T> : IAsyncEnumerator<T>, IAsyncEnumerable<T>
{
public static readonly EmptyAsyncEnumerator<T> Instance = new EmptyAsyncEnumerator<T>();
public T Current => default;
public ValueTask DisposeAsync() => default;
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return this;
}
public ValueTask<bool> MoveNextAsync() => new ValueTask<bool>(false);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With