The following prints IAsyncDisposable.DisposeAsync():
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
await foreach (var i in new AsyncEnumerable())
{
}
struct AsyncEnumerable : IAsyncEnumerable<int>
{
public AsyncEnumerator GetAsyncEnumerator(CancellationToken token) => new AsyncEnumerator();
IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(CancellationToken token) => new AsyncEnumerator();
}
struct AsyncEnumerator : IAsyncEnumerator<int>
{
public int Current => 0;
public async ValueTask<bool> MoveNextAsync() => false;
public async ValueTask DisposeAsync() { Console.WriteLine("DisposeAsync()"); }
async ValueTask IAsyncDisposable.DisposeAsync() { Console.WriteLine("IAsyncDisposable.DisposeAsync()"); }
}
See sharplab.io.
From async-streams spec:
The compiler will bind to the pattern-based APIs if they exist, preferring those over using the interface (the pattern may be satisfied with instance methods or extension methods).
The following prints
IAsyncDisposable.DisposeAsync():See sharplab.io.
From async-streams spec: