Repository: dotnet/runtime
File: src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs (C#)

Code before:
                ObjectDisposedException.ThrowIf(_disposed, _innerStream);
                throw new NotSupportedException("Synchronous operations are not supported.");
            }

            public override int Read(byte[] buffer, int offset, int count)
            {
                ObjectDisposedException.ThrowIf(_disposed, _innerStream);
                throw new NotSupportedException("Synchronous operations are not supported.");
            }

            public override void Write(byte[] buffer, int offset, int count)
            {
                ObjectDisposedException.ThrowIf(_disposed, _innerStream);
                throw new NotSupportedException("Synchronous operations are not supported.");
            }

            public override ValueTask<int> ReadAsync(Memory<byte> buffer, System.Threading.CancellationToken cancellationToken = default) => _innerStream.ReadAsync(buffer, cancellationToken);
            public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, System.Threading.CancellationToken cancellationToken = default) => _innerStream.WriteAsync(buffer, cancellationToken);
            public override Task FlushAsync(System.Threading.CancellationToken cancellationToken = default) => _innerStream.FlushAsync(cancellationToken);

            protected override void Dispose(bool disposing)
            {
                if (_disposed) return;

                _disposed = true;
                _innerStream.Dispose();
            }

            public override ValueTask DisposeAsync()
            {
                if (_disposed) return default;

                _disposed = true;
                return _innerStream.DisposeAsync();
            }

            public override void Close() => _innerStream.Close();
        }
    }

    /// <summary>Provides a disposable, enumerable tuple of two streams.</summary>
    public class StreamPair : IDisposable, IAsyncDisposable, IEnumerable<Stream>
    {
        public readonly Stream Stream1, Stream2;

        public StreamPair(Stream stream1, Stream stream2)
        {
            Stream1 = stream1;
            Stream2 = stream2;
        }


Review comment (suggestion):
The `Dispose(bool)` method unconditionally calls `_innerStream.Dispose()` even when `disposing` is false (finalizer path). The `disposing` parameter should be checked, and the inner stream should only be disposed when `disposing` is true. Additionally, calling `_innerStream.Dispose()` is a synchronous operation that could perform blocking IO, which contradicts the purpose of `AsyncOnlyStream`. Consider either: (1) not disposing the inner stream in synchronous `Dispose` and requiring callers to use `DisposeAsync`, or (2) checking the `disposing` parameter properly.
```suggestion
                if (disposing)
                {
                    _innerStream.Dispose();
                }
```

Code after:
                ObjectDisposedException.ThrowIf(_disposed, _innerStream);
                throw new NotSupportedException("Synchronous operations are not supported.");
            }

            public override int Read(byte[] buffer, int offset, int count)
            {
                ObjectDisposedException.ThrowIf(_disposed, _innerStream);
                throw new NotSupportedException("Synchronous operations are not supported.");
            }

            public override void Write(byte[] buffer, int offset, int count)
            {
                ObjectDisposedException.ThrowIf(_disposed, _innerStream);
                throw new NotSupportedException("Synchronous operations are not supported.");
            }

            public override ValueTask<int> ReadAsync(Memory<byte> buffer, System.Threading.CancellationToken cancellationToken = default) => _innerStream.ReadAsync(buffer, cancellationToken);
            public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, System.Threading.CancellationToken cancellationToken = default) => _innerStream.WriteAsync(buffer, cancellationToken);
            public override Task FlushAsync(System.Threading.CancellationToken cancellationToken = default) => _innerStream.FlushAsync(cancellationToken);

            protected override void Dispose(bool disposing)
            {
                if (_disposed) return;

                _disposed = true;
                if (disposing)
                {
                    _innerStream.Dispose();
                }
            }

            public override ValueTask DisposeAsync()
            {
                if (_disposed) return default;

                _disposed = true;
                return _innerStream.DisposeAsync();
            }

            public override void Close()
            {
                throw new NotSupportedException("Synchronous operations are not supported.");
            }
        }
    }

    /// <summary>Provides a disposable, enumerable tuple of two streams.</summary>
    public class StreamPair : IDisposable, IAsyncDisposable, IEnumerable<Stream>
    {
        public readonly Stream Stream1, Stream2;