Skip to content

Instantly share code, notes, and snippets.

@benaadams
Last active November 26, 2015 23:25
Show Gist options
  • Save benaadams/74eb6be3e2bb5c1c2a64 to your computer and use it in GitHub Desktop.
Save benaadams/74eb6be3e2bb5c1c2a64 to your computer and use it in GitHub Desktop.
Stream Evolution in Interfaces (Mixins+Streams)
// Interface segregation (Combined Mixin+Non-mixin)
// For no-mixins version see https://gist.github.com/benaadams/d35ff5c534a43fd6c89d
// For mixins/generic constraints version see https://gist.github.com/benaadams/77c6e7aa34aae92b876a
// Do something with sync Reading, Seeking, Disposable stream (Generic Constraints)
public static void DoSomething<T>(T stream) where T : IBlockingReader, ISeekable, ISizable, IDisposable
{
stream.ReadByte();
stream.SetLength(6);
stream.Position = 5;
stream.Dispose();
}
// Do something with sync Reading, Seeking, Disposable stream (Pre-Mixin)
public static void DoSomething(ISeekableDuplexStream stream)
{
stream.ReadByte();
stream.SetLength(6);
stream.Position = 5;
stream.Dispose();
}
///
using System.Threading;
using System.Threading.Tasks;
// Interface segregation
namespace System.IO
{
/* .NET Framework 1.1 */
public interface IBlockingReader
{
int ReadByte();
int Read(byte[] buffer, int offset, int count);
}
public interface IBlockingWriter
{
void Flush();
void WriteByte(byte value);
void Write(byte[] buffer, int offset, int count);
}
public interface ISeekable
{
long Position { get; set; }
long Length { get; }
long Seek(long offset, SeekOrigin origin);
}
public interface ISizable
{
void SetLength(long value);
}
/* .NET Framework 4.5 */
public interface IReaderAsync
{
Task<int> ReadAsync(byte[] buffer, int offset, int count);
Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken);
}
public interface IWriterAsync
{
Task FlushAsync();
Task FlushAsync(CancellationToken cancellationToken);
Task WriteAsync(byte[] buffer, int offset, int count);
Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken);
}
// Pre-Mixin
namespace Mixin
{
/* .NET Framework 1.1 */
public interface IBlockingDuplex : IBlockingReader, IBlockingWriter { }
public interface ISeekableReader : IBlockingReader, ISeekable { }
public interface ISeekableWriter : IBlockingWriter, ISeekable, ISizable { }
public interface ISeekableDuplex : ISeekableReader, ISeekableWriter { }
/* .NET Framework 4.5 */
public interface IDuplexAsync : IReaderAsync, IWriterAsync { }
namespace Stream
{
/* .NET Framework 1.1 */
public interface IBlockingReadStream : IBlockingReader, IDisposable { }
public interface IBlockingWriteStream : IBlockingWriter, IDisposable { }
public interface IBlockingDuplexStream : IBlockingReadStream, IBlockingWriteStream { }
public interface ISeekableStream : ISeekable, IDisposable { }
public interface ISeekableReadStream : IBlockingReadStream, ISeekableStream, ISeekableReader { }
public interface ISeekableWriteStream : IBlockingWriteStream, ISeekableStream, ISeekableWriter { }
public interface ISeekableDuplexStream : ISeekableReadStream, ISeekableWriteStream, IBlockingDuplexStream, ISeekableDuplex { }
/* .NET Framework 4.5 */
public interface IReadStreamAsync : IReaderAsync, IDisposable { }
public interface IWriteStreamAsync : IWriterAsync, IDisposable { }
public interface IDuplexStreamAsync : IReadStreamAsync, IWriteStreamAsync, IDuplexAsync { }
}
}
namespace Extensions
{
public static partial class ReaderWriterExtensions
{
/* .NET Framework 4.0 */
private const int _DefaultCopyBufferSize = 81920;
public static void CopyTo(this IBlockingReader source, IBlockingWriter destination)
{
source.CopyTo(destination, _DefaultCopyBufferSize);
}
public static void CopyTo(this IBlockingReader source, IBlockingWriter destination, int bufferSize)
{
byte[] buffer = new byte[bufferSize];
int read;
while ((read = source.Read(buffer, 0, buffer.Length)) != 0)
destination.Write(buffer, 0, read);
}
/* .NET Framework 4.5 */
public static Task CopyToAsync(this IReaderAsync source, IWriterAsync destination)
{
return source.CopyToAsync(destination, _DefaultCopyBufferSize, CancellationToken.None);
}
public static Task CopyToAsync(this IReaderAsync source, IWriterAsync destination, int bufferSize)
{
return source.CopyToAsync(destination, bufferSize, CancellationToken.None);
}
public static async Task CopyToAsync(this IReaderAsync source, IWriterAsync destination, int bufferSize, CancellationToken cancellationToken)
{
byte[] buffer = new byte[bufferSize];
int bytesRead;
while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
{
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
}
}
}
namespace Implementer
{
public static partial class ReaderWriterImplementerExtensions
{
/* .NET Framework 1.1 */
public static int ReadByteInner(this IBlockingReader source)
{
byte[] oneByteArray = new byte[1];
int r = source.Read(oneByteArray, 0, 1);
if (r == 0)
return -1;
return oneByteArray[0];
}
public static void WriteByteInner(this IBlockingWriter destination, byte value)
{
byte[] oneByteArray = new byte[1];
oneByteArray[0] = value;
destination.Write(oneByteArray, 0, 1);
}
}
}
}
}
#if !FEATURE_CORECLR
namespace System.IO
{
/* .NET Framework 1.1 */
public interface IStream
{
void Close();
}
public interface IAsyncReader
{
IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state);
int EndRead(IAsyncResult asyncResult);
}
public interface IAsyncWriter
{
IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state);
void EndWrite(IAsyncResult asyncResult);
}
/* .NET Framework 2.0 */
public interface IReadTimeout
{
int ReadTimeout { get; set; }
}
public interface IWriteTimeout
{
int WriteTimeout { get; set; }
}
// Pre-Mixin
namespace Mixin
{
/* .NET Framework 2.0 */
public interface IAsyncTimeoutReader : IAsyncReader, IReadTimeout { }
public interface IAsyncTimeoutWriter : IAsyncWriter, IWriteTimeout { }
/* .NET Framework 1.1 */
public interface IAsyncReadStream : IAsyncReader, IStream { }
public interface IAsyncWriteStream : IAsyncWriter, IStream { }
public interface IAsyncDuplexStream : IAsyncReadStream, IAsyncWriteStream { }
namespace Stream
{
/* .NET Framework 2.0 */
public interface IAsyncTimeoutReadStream : IAsyncReadStream, IAsyncTimeoutReader { }
public interface IAsyncTimeoutWriteStream : IAsyncWriteStream, IAsyncTimeoutWriter { }
public interface IAsyncTimeoutDuplexStream : IAsyncTimeoutReadStream, IAsyncTimeoutWriteStream { }
}
}
namespace Extensions
{
public static partial class StreamExtensions
{
/* .NET Framework 4.5 */
public static Task<int> ReadAsync(this IAsyncReader source, byte[] buffer, int offset, int count)
{
return Task<int>.Factory.FromAsync(source.BeginRead, source.EndRead, buffer, offset, count, null);
}
public static Task<int> ReadAsync(this IAsyncReader source, byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return cancellationToken.IsCancellationRequested
? Task.FromCanceled<int>(cancellationToken)
: Task<int>.Factory.FromAsync(source.BeginRead, source.EndRead, buffer, offset, count, null);
}
public static Task WriteAsync(this IAsyncWriter destination, byte[] buffer, int offset, int count)
{
return Task.Factory.FromAsync(destination.BeginWrite, destination.EndWrite, buffer, offset, count, null);
}
public static Task WriteAsync(this IAsyncWriter destination, byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return cancellationToken.IsCancellationRequested
? Task.FromCanceled<int>(cancellationToken)
: Task.Factory.FromAsync(destination.BeginWrite, destination.EndWrite, buffer, offset, count, null);
}
}
namespace Conversion
{
public static partial class StreamLegacyConverterExtensions
{
public static IAsyncReader AsAsyncReader(this IReaderAsync stream) => null;
// Use timed CTS
public static IAsyncTimeoutReader AsAsyncTimeoutReader(this IReaderAsync stream) => null;
// ...
}
}
}
}
#endif // !FEATURE_CORECLR
/*
#if FEATURE_REMOTING
public class Stream : MarshalByRefObject, ISeekableDuplexStream, IAsyncTimeoutDuplexStream, IDuplexStreamAsync
#endif
#if !FEATURE_REMOTING && !FEATURE_CORECLR
public class Stream : ISeekableDuplexStream, IAsyncTimeoutDuplexStream, IDuplexStreamAsync
#endif
#if FEATURE_CORECLR
public class Stream : ISeekableDuplexStream, IDuplexStreamAsync
#endif
{
public static readonly Stream Null = new NullStream();
public static Stream Synchronized(Stream stream)
{
}
// ...
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment