如何将标准MemoryStream赋值给继承自它的自定义类MemoryStream2
嘿,我来帮你捋清楚这个问题!首先得明确:你碰到的Cannot assign to 'this' because it is read-only错误是必然的——在C#里this是个只读引用,你没法直接把另一个实例赋值给它,就算强制类型转换也没用,毕竟赋值语句的左边必须是可修改的变量才行。
那回到你的核心需求:把普通的MemoryStream转成自定义的MemoryStream2,还不想复制流里的数据,该怎么实现?
为什么继承这条路走不通(不复制数据的前提下)
MemoryStream的内部缓冲区是私有成员,它也没提供公开方法让你直接替换或复用这个缓冲区。所以如果你的MemoryStream2是继承自MemoryStream,那你只能创建全新的MemoryStream2实例,把原流的数据复制进去,没法直接复用原流的内存。
如果能接受复制数据,那可以这么修改构造函数:
public MemoryStream2(System.IO.MemoryStream ms) : base(ms.ToArray()) { this.ReferenceId = DateTime.Now.ToString(); // 要是需要保留原流的读取位置,别忘了同步Position this.Position = ms.Position; }
但这显然不符合你“不复制数据”的要求,所以得换个思路。
最佳方案:用组合代替继承
既然继承没法直接复用原流,那我们换个思路——让MemoryStream2包装一个MemoryStream实例,而不是继承它。具体来说,让MemoryStream2实现Stream抽象类,内部持有一个MemoryStream对象,把所有流操作都委托给这个内部对象,同时加上你自己的ReferenceId属性。
这种方式的好处是:可以直接把原有的MemoryStream传入,完全复用它的缓冲区,不用复制任何数据。代码示例如下:
public class MemoryStream2 : System.IO.Stream { private readonly System.IO.MemoryStream _innerStream; public string ReferenceId { get; set; } = ""; // 无参构造:自己创建内部流 public MemoryStream2() { _innerStream = new System.IO.MemoryStream(); ReferenceId = DateTime.Now.ToString(); } // 用字节数组构造 public MemoryStream2(byte[] buffer) { _innerStream = new System.IO.MemoryStream(buffer); ReferenceId = DateTime.Now.ToString(); } // 用现有MemoryStream构造——重点在这!直接复用原流 public MemoryStream2(System.IO.MemoryStream ms) { _innerStream = ms; ReferenceId = DateTime.Now.ToString(); } // 重写Stream的所有抽象/虚成员,委托给_innerStream public override bool CanRead => _innerStream.CanRead; public override bool CanSeek => _innerStream.CanSeek; public override bool CanWrite => _innerStream.CanWrite; public override long Length => _innerStream.Length; public override long Position { get => _innerStream.Position; set => _innerStream.Position = value; } public override void Flush() => _innerStream.Flush(); public override int Read(byte[] buffer, int offset, int count) => _innerStream.Read(buffer, offset, count); public override long Seek(long offset, System.IO.SeekOrigin origin) => _innerStream.Seek(offset, origin); public override void SetLength(long value) => _innerStream.SetLength(value); public override void Write(byte[] buffer, int offset, int count) => _innerStream.Write(buffer, offset, count); }
这样你就可以直接把返回的MemoryStream传入MemoryStream2的构造函数,完美复用原流的数据,还能带上你的ReferenceId。
虽然这种方式需要你写一堆委托代码,但这是实现你需求的最优解——正如你自己编辑里提到的,组合确实是目前最好的方案,稍微做点代码重构就能解决问题啦。
备注:内容来源于stack exchange,提问作者George

