File: System\ServiceModel\Channels\DelegatingStream.cs
Web Access
Project: src\src\System.ServiceModel.Primitives\src\System.ServiceModel.Primitives.csproj (System.ServiceModel.Primitives)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
 
using System.IO;
using System.Runtime;
using System.Threading;
using System.Threading.Tasks;
 
namespace System.ServiceModel.Channels
{
    // Base Stream that delegates all its methods to another Stream.
    public abstract class DelegatingStream : Stream
    {
        private bool _disposed;
 
        protected DelegatingStream(Stream stream)
        {
            BaseStream = stream ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(stream));
        }
 
        protected Stream BaseStream { get; }
        public override bool CanRead => BaseStream.CanRead;
        public override bool CanSeek => BaseStream.CanSeek;
        public override bool CanTimeout => BaseStream.CanTimeout;
        public override bool CanWrite => BaseStream.CanWrite;
        public override long Length => BaseStream.Length;
 
        protected override void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    BaseStream.Dispose();
                }
 
                _disposed = true;
            }
 
            base.Dispose(disposing);
        }
 
        public override async ValueTask DisposeAsync()
        {
            if (!_disposed)
            {
                await BaseStream.DisposeAsync();
                GC.SuppressFinalize(this);
                _disposed = true;
            }
 
            await base.DisposeAsync();
        }
 
        public override long Position
        {
            get => BaseStream.Position;
            set => BaseStream.Position = value;
        }
 
        public override int ReadTimeout
        {
            get => BaseStream.ReadTimeout;
            set => BaseStream.ReadTimeout = value;
        }
 
        public override int WriteTimeout
        {
            get => BaseStream.WriteTimeout;
            set => BaseStream.WriteTimeout = value;
        }
 
        public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken) => BaseStream.CopyToAsync(destination, bufferSize, cancellationToken);
        public override void Flush() => BaseStream.Flush();
        public override Task FlushAsync(CancellationToken cancellationToken) => BaseStream.FlushAsync(cancellationToken);
        public override long Seek(long offset, SeekOrigin origin) => BaseStream.Seek(offset, origin);
        public override void SetLength(long value) => BaseStream.SetLength(value);
 
        // Do NOT override Read(Span<byte buffer) unless also providing implementations for all types derived from DelegatingStream
        // as the parent class won't have Read(byte[] buffer, int offset, int count) called. This is because BaseStream.Read(Span<byte>)
        // will forward the call to BaseStream.Read(byte[],int,int) and won't go through the parent implementation.
        // public override int Read(Span<byte> buffer) => BaseStream.Read(buffer);
 
        // Do NOT override BeginRead/EndRead in types derived from DelegatingStream otherwise the parent BeginRead and ReadAsync will both get called
        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) => ReadAsync(buffer, offset, count).ToApm(callback, state);
        public override int EndRead(IAsyncResult asyncResult) => asyncResult.ToApmEnd<int>();
        public override int Read(byte[] buffer, int offset, int count) => BaseStream.Read(buffer, offset, count);
        public override int ReadByte() => BaseStream.ReadByte();
        public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => BaseStream.ReadAsync(buffer, offset, count, cancellationToken);
        public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default) => BaseStream.ReadAsync(buffer, cancellationToken);
 
        // Do NOT override Write(ReadOnlySpan<byte> buffer) unless also providing implementations for all types derived from DelegatingStream.
        // This is for similar reasons as commented for Read(Span<byte>)
        //public override void Write(ReadOnlySpan<byte> buffer) => BaseStream.Write(buffer);
 
        // Do NOT override BeginWrite/EndWrite in types derived from DelegatingStream otherwise the parent BeginWrite and WriteAsync will both get called
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) => WriteAsync(buffer, offset, count).ToApm(callback, state);
        public override void EndWrite(IAsyncResult asyncResult) => asyncResult.ToApmEnd();
 
        public override void Write(byte[] buffer, int offset, int count) => BaseStream.Write(buffer, offset, count);
        public override void WriteByte(byte value) => BaseStream.WriteByte(value);
        public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => BaseStream.WriteAsync(buffer, offset, count, cancellationToken);
        public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default) => BaseStream.WriteAsync(buffer, cancellationToken);
    }
}