Created
March 20, 2020 11:10
-
-
Save daiplusplus/23c990c6b5f4e8e3cb07d45da66d6afa to your computer and use it in GitHub Desktop.
ProxyStream for .NET Framework, .NET Standard and .NET Core
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
using System; | |
using System.IO; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace WhyAreYouCopyingCodeFromGitHub | |
{ | |
/// <summary> | |
/// <para>This class directly subclasses <see cref="System.IO.Stream"/> and overrides every virtual member. All members directly invoke their corresponding method on the wrapped <see cref="System.IO.Stream"/> object. Only the members <see cref="Stream.CreateWaitHandle"/>, <c>Stream.CreateObjRef</c> (not present in .NET Standard) and <see cref="Stream.ObjectInvariant"/> are not overridden.</para> | |
/// <para>This class is intended to be used as the base class for a subclass that only wants to override individual methods when proxying a <see cref="Stream"/> instead of implementing all of Stream's abstract methods. This class can also be instantiated directly and used as a preventative measure against consumers of your <see cref="System.IO.Stream"/> objects from being disposed by using the <see cref="LeaveOpen"/> constructor parameter.</para> | |
/// </summary> | |
public class ProxyStream : Stream | |
{ | |
/// <summary>Constructor.</summary> | |
/// <param name="stream">The stream to wrap/proxy. Required. Cannot be null.</param> | |
/// <param name="leaveOpen">When <c>true</c> then <see cref="ProxyStream.Dispose(bool)"/> will NOT dispose of <paramref name="stream"/>, otherwise <paramref name="stream"/> will be disposed when this <see cref="ProxyStream"/> is disposed.</param> | |
public ProxyStream( Stream stream, Boolean leaveOpen ) | |
{ | |
this.Stream = stream ?? throw new ArgumentNullException(nameof(stream)); | |
this.LeaveOpen = leaveOpen; | |
} | |
/// <summary>When <c>true</c> then <see cref="ProxyStream.Dispose(bool)"/> will NOT dispose of <see cref="ProxyStream.Stream"/>, otherwise <see cref="ProxyStream.Stream"/> will be disposed when this <see cref="ProxyStream"/> is disposed.</summary> | |
public Boolean LeaveOpen { get; } | |
/// <summary>The wrapped/proxied <see cref="System.IO.Stream"/> object.</summary> | |
public Stream Stream { get; } | |
public override Boolean CanRead => this.Stream.CanRead; | |
public override Boolean CanSeek => this.Stream.CanSeek; | |
public override Boolean CanTimeout => this.Stream.CanTimeout; | |
public override Boolean CanWrite => this.Stream.CanWrite; | |
public override Int64 Length => this.Stream.Length; | |
public override Int64 Position | |
{ | |
get => this.Stream.Position; | |
set => this.Stream.Position = value; | |
} | |
public override Int32 ReadTimeout | |
{ | |
get => this.Stream.ReadTimeout; | |
set => this.Stream.ReadTimeout = value; | |
} | |
public override Int32 WriteTimeout | |
{ | |
get => this.Stream.WriteTimeout; | |
set => this.Stream.WriteTimeout = value; | |
} | |
public override IAsyncResult BeginRead( Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state ) | |
{ | |
return this.Stream.BeginRead( buffer, offset, count, callback, state ); | |
} | |
public override IAsyncResult BeginWrite( Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state ) | |
{ | |
return this.Stream.BeginWrite( buffer, offset, count, callback, state ); | |
} | |
public override Task CopyToAsync( Stream destination, Int32 bufferSize, CancellationToken cancellationToken ) | |
{ | |
return this.Stream.CopyToAsync( destination, bufferSize, cancellationToken ); | |
} | |
public override Int32 EndRead( IAsyncResult asyncResult ) | |
{ | |
return this.Stream.EndRead( asyncResult ); | |
} | |
public override void EndWrite( IAsyncResult asyncResult ) | |
{ | |
this.Stream.EndWrite( asyncResult ); | |
} | |
public override void Flush() | |
{ | |
this.Stream.Flush(); | |
} | |
public override Task FlushAsync( CancellationToken cancellationToken ) | |
{ | |
return this.Stream.FlushAsync( cancellationToken ); | |
} | |
public override Object InitializeLifetimeService() | |
{ | |
return this.Stream.InitializeLifetimeService(); | |
} | |
public override Int32 Read( Byte[] buffer, Int32 offset, Int32 count ) | |
{ | |
return this.Stream.Read( buffer, offset, count ); | |
} | |
public override Task<Int32> ReadAsync( Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken ) | |
{ | |
return this.Stream.ReadAsync( buffer, offset, count, cancellationToken ); | |
} | |
public override Int32 ReadByte() | |
{ | |
return this.Stream.ReadByte(); | |
} | |
public override Int64 Seek( Int64 offset, SeekOrigin origin ) | |
{ | |
return this.Stream.Seek( offset, origin ); | |
} | |
public override void SetLength( Int64 value ) | |
{ | |
this.Stream.SetLength( value ); | |
} | |
public override void Write( Byte[] buffer, Int32 offset, Int32 count ) | |
{ | |
this.Stream.Write( buffer, offset, count ); | |
} | |
public override Task WriteAsync( Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken ) | |
{ | |
return this.Stream.WriteAsync( buffer, offset, count, cancellationToken ); | |
} | |
public override void WriteByte( Byte value ) | |
{ | |
this.Stream.WriteByte( value ); | |
} | |
#region Close + Dispose | |
/// <summary>NOTE: If <see cref="LeaveOpen"/> is true, then <see cref="Stream"/> will be closed.</summary> | |
public override void Close() | |
{ | |
// Stream::Close() calls `Stream::Dispose( disposing: true );` | |
// and then `GC.SuppressFinalize(this);`. | |
// So there's no need for custom logic here... or is there? | |
if( this.LeaveOpen ) | |
{ | |
} | |
else | |
{ | |
this.Stream.Close(); | |
} | |
base.Close(); | |
} | |
protected override void Dispose( Boolean disposing ) | |
{ | |
if( this.LeaveOpen ) | |
{ | |
} | |
else | |
{ | |
this.Stream.Dispose(); | |
} | |
// Don't call `base.Dispose` because *this* method (`Dispose(bool)` is invoked from `Stream::Dispose()` already) | |
//base.Dispose(); | |
} | |
#endregion | |
// [Obsolete] | |
// protected override WaitHandle CreateWaitHandle() | |
// { | |
// throw new NotSupportedException(); | |
// } | |
// | |
// [Obsolete] | |
// protected override void ObjectInvariant() | |
// { | |
// throw new NotSupportedException(); | |
// } | |
// | |
// public override ObjRef CreateObjRef( Type requestedType ) // Not present in .NET Standard | |
// { | |
// return this.Stream.CreateObjRef( requestedType ); | |
// } | |
#region Object virtual | |
public override Boolean Equals( Object obj ) | |
{ | |
return this.Stream.Equals( obj ); | |
} | |
public override Int32 GetHashCode() | |
{ | |
return this.Stream.GetHashCode(); | |
} | |
public override String ToString() | |
{ | |
return this.Stream.ToString(); | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment