我需要包装现有的Stream实例,并在读写时实现一些附加逻辑。
包装器也必须是Stream。它将被传递给第三方API,它需要Stream (因此,我无法提取接口并使用DispatchProxy)。
显而易见的方法是像这样从Stream继承:
public sealed class WrappedStream : Stream
{
private readonly Stream inner;
public WrappedStream(Stream inner)
{
this.inner = inner;
}
public override bool CanRead => inner.CanRead;
public override bool CanSeek => inner.CanSeek;
public override bool CanWrite => inner.CanWrite;
public override long Length => inner.Length;
public override long Position
{
get => inner.Position;
set => inner.Position = value;
}
public override void Flush() => inner.Flush();
public override long Seek(long offset, SeekOrigin origin) => inner.Seek(offset, origin);
public override void SetLength(long value) => inner.SetLength(value);
public override int Read(byte[] buffer, int offset, int count)
{
// TODO: implement additional logic here
return inner.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
// TODO: implement additional logic here
inner.Write(buffer, offset, count);
}
}但是Stream中的所有抽象方法都是用于同步I/O的,我怀疑,在只实现抽象方法的情况下,基本Stream将执行异步过同步。
因为inner可以支持异步,所以我不想用异步过同步来破坏这种支持。在水龙头中有几个虚拟的APM和Stream方法,但是为了正确的异步I/O支持,它们中的哪一个应该被覆盖?
更新
我读了“给执行人员的说明”。如果继承类型没有实现自己的Stream方法,基本Begin...就会进行异步过同步.例如,FileStream使用自己的异步实现。因此,尽管基本实现可以工作,但从异步I/O的角度来看,它并不有效。
发布于 2020-05-07 09:14:18
来自文档
在实现
Stream的派生类时,必须为Read(Byte[], Int32, Int32)和Write(Byte[], Int32, Int32)方法提供实现。异步方法ReadAsync(Byte[], Int32, Int32)、WriteAsync(Byte[], Int32, Int32)和CopyToAsync(Stream)在其实现中使用同步方法Read(Byte[], Int32, Int32)和Write(Byte[], Int32, Int32)。因此,Read(Byte[], Int32, Int32)和Write(Byte[], Int32, Int32)的实现将正确地与异步方法一起工作。ReadByte()和WriteByte(Byte)的默认实现创建一个新的单元素字节数组,然后调用Read(Byte[], Int32, Int32)和Write(Byte[], Int32, Int32)的实现。当您从Stream派生时,我们建议您重写这些方法来访问您的内部缓冲区(如果您有),以获得更好的性能。您还必须提供CanRead、CanSeek、CanWrite、Flush()、Length、Position、Seek(Int64, SeekOrigin)和SetLength(Int64)的实现。 不要覆盖Close()方法,而是将所有Stream清理逻辑放在Dispose(Boolean)方法中。有关更多信息,请参见实现Dispose方法。
总之,需要实现一组方法/属性:
Read(..),Write(..),CanWrite,Flush(..),Length,Position,Seek(..)和`SetLength(.)如果您可以提供更好的默认实现,那么所有其他虚拟方法都应该被覆盖。
因此,如果您能够实现一个真正的异步ReadAsync(..)和WriteAsync(..),那么您应该这样做。FlushAsync(..)、CopyToAsync(..)和DisposeAsync(..)也是如此。
还请看一下源代码
...
public virtual int ReadTimeout
{
get => throw new InvalidOperationException(SR.InvalidOperation_TimeoutsNotSupported);
set => throw new InvalidOperationException(SR.InvalidOperation_TimeoutsNotSupported);
}
public virtual int WriteTimeout
{
get => throw new InvalidOperationException(SR.InvalidOperation_TimeoutsNotSupported);
set => throw new InvalidOperationException(SR.InvalidOperation_TimeoutsNotSupported);
}
...如果您想要支持ReadTimeout和WriteTimeout,您也应该重写它。
https://stackoverflow.com/questions/61653712
复制相似问题