Created
December 6, 2022 20:35
-
-
Save jozkee/27aa6ab757e8d87dc3ef27d7be69d9d3 to your computer and use it in GitHub Desktop.
Implementation of NewStream with Template Method Pattern
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace System.IO; | |
public abstract class NewStream : Stream | |
{ | |
private bool _disposed; | |
public sealed override int Read(byte[] buffer, int offset, int count) | |
{ | |
ValidateBufferArguments(buffer, offset, count); | |
return Read(buffer.AsSpan(offset, count)); | |
} | |
public sealed override int Read(Span<byte> buffer) | |
{ | |
EnsureCanRead(); | |
EnsureNotDisposed(); | |
return ReadCore(buffer); | |
} | |
protected abstract int ReadCore(Span<byte> buffer); | |
public sealed override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) | |
{ | |
ValidateBufferArguments(buffer, offset, count); | |
return ReadAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask(); | |
} | |
public sealed override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default) | |
{ | |
EnsureCanRead(); | |
EnsureNotDisposed(); | |
return base.ReadAsync(buffer, cancellationToken); | |
} | |
public sealed override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) | |
=> TaskToApm.Begin(ReadAsync(buffer, offset, count, CancellationToken.None), callback, state); | |
public override int EndRead(IAsyncResult asyncResult) | |
{ | |
EnsureNotDisposed(); | |
return TaskToApm.End<int>(asyncResult); | |
} | |
protected abstract ValueTask<int> ReadCoreAsync(Memory<byte> buffer, CancellationToken cancellationToken); | |
public sealed override void Write(byte[] buffer, int offset, int count) | |
{ | |
ValidateBufferArguments(buffer, offset, count); | |
Read(buffer.AsSpan(offset, count)); | |
} | |
public sealed override void Write(ReadOnlySpan<byte> buffer) | |
{ | |
EnsureCanWrite(); | |
EnsureNotDisposed(); | |
WriteCore(buffer); | |
} | |
protected abstract void WriteCore(ReadOnlySpan<byte> buffer); | |
public sealed override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) | |
{ | |
ValidateBufferArguments(buffer, offset, count); | |
return WriteAsync(buffer.AsMemory(offset, count)).AsTask(); | |
} | |
public sealed override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default) | |
{ | |
EnsureCanWrite(); | |
EnsureNotDisposed(); | |
return WriteCoreAsync(buffer, cancellationToken); | |
} | |
public sealed override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) | |
=> TaskToApm.Begin(WriteAsync(buffer, offset, count, CancellationToken.None), callback, state); | |
public override void EndWrite(IAsyncResult asyncResult) | |
{ | |
EnsureNotDisposed(); | |
TaskToApm.End(asyncResult); | |
} | |
protected abstract ValueTask WriteCoreAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken); | |
public override long Seek(long offset, SeekOrigin origin) | |
{ | |
EnsureNotDisposed(); | |
EnsureCanSeek(); | |
long pos = origin switch | |
{ | |
SeekOrigin.Begin => offset, | |
SeekOrigin.Current => Position + offset, | |
SeekOrigin.End => Length + offset, | |
_ => throw new ArgumentException("Invalid seek origin", nameof(origin)) | |
}; | |
if (pos < 0) | |
{ | |
throw new ArgumentOutOfRangeException(); | |
} | |
return SeekCore(offset, origin); | |
} | |
protected abstract long SeekCore(long offset, SeekOrigin origin); | |
public override void SetLength(long value) | |
{ | |
EnsureNotDisposed(); | |
EnsureCanSeek(); | |
EnsureCanWrite(); | |
if (value < 0) | |
{ | |
throw new ArgumentOutOfRangeException(nameof(value)); | |
} | |
SetLengthCore(value); | |
} | |
protected abstract void SetLengthCore(long value); | |
protected override void Dispose(bool disposing) | |
{ | |
_disposed = true; | |
base.Dispose(disposing); | |
} | |
private void EnsureCanRead() | |
{ | |
if (!CanRead) throw new InvalidOperationException("Stream is unreadable."); | |
} | |
private void EnsureCanWrite() | |
{ | |
if (!CanWrite) throw new InvalidOperationException("Stream is unwrittable."); | |
} | |
private void EnsureCanSeek() | |
{ | |
if (!CanSeek) throw new InvalidOperationException("Stream is unseekable."); | |
} | |
private void EnsureNotDisposed() => ObjectDisposedException.ThrowIf(_disposed, this); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment