.NET Stream类的设计是否很差?

I. *_*edy 18 .net c# oop abstract-class stream

我花了很多时间熟悉.NET Stream类.通常我通过研究专业的,商业级的框架的类设计来学到很多东西,但我不得不说这里的东西不太好闻.

System.IO.Stream是一个表示字节序列的抽象类.它有10个抽象方法/属性:Read, Write, Flush, Length, SetLength, Seek, Position, CanRead, CanWrite, CanSeek.如此多的抽象成员使得派生起来很麻烦,因为你必须覆盖所有这些方法,即使大多数最终只是抛出NotImplemented.

Stream类的用户希望能够打电话CanRead,CanWriteCanSeek找出了数据流的能力,或者我想先走一步,打电话Read,Write或者Seek看它是否抛出NotImplemented.它只是我,还是这个糟糕的设计?

虽然现在有很多尼特我想用挑Stream一流的设计,主要的一个,我想请教一下的是:他们为什么不使用界面,比如IReadable,IWriteable,ISeekable,而不是?然后,新的Stream类可以从它支持的接口中优雅地派生.这不是面向对象的做事方式吗?或者我错过了什么?

更新:有人指出,值CanRead 可以在运行时更改 - 例如,如果a FileStream关闭 - 并且采取了这一点.但是,我仍然不相信这是一个很好的设计.从我来自哪里,尝试从已经关闭的文件中读取是一个错误,或者至少是一个特殊情况.(因此抛出异常是处理这种情况的一种自然方式.)

这是否意味着每次我要Read离开时Stream,我应该检查一下CanRead?并且这是否意味着我应该设置一个锁以避免竞争条件,如果值可能在CanRead呼叫和Read呼叫之间的某个时间发生变化?

2010年8月7日更新:这里的共识似乎是Stream设计非常好.但是让我再一次要求100%肯定:人们每次从流中读取内容时都会写这样的东西?

//  s is a Stream

lock(s)
{
    if (s.CanRead)
    {
        s.Read(buf, 0, buf.Length);
    }
}
Run Code Online (Sandbox Code Playgroud)

Bob*_*Bob 10

我认为课程设计得很好.我宁愿检查一个属性然后尝试做某事并且必须捕获异常.在具有多个"类型"的流类型的情况下,接口不足.从一个获取可读写流的方法返回什么类型?我同意设计不是真正的面向对象设计,但你真的想以这种方式处理流吗?如果流关闭或其他更改,某些属性可能会更改,在这种情况下会发生什么?

我认为这个问题提出了一个非常有趣的实验,为什么不尝试设计自己的流相关类.在CodePlex或Google Code上发布您的重新设计,这将是一个很好的学习经验,并将导致一个潜在有用的库供其他人使用.

  • 不,你可以得到一个实现IReadable和IWritable的对象. (5认同)
  • 因此,如果流是可读写的,你会得到一个IReadableWritableStream吗? (2认同)

Dav*_*vid 9

使用接口意味着无法在运行时更改"CanRead"的值."FileStream"类根据文件的当前状态更改"CanRead"属性.

  • 吞噬elysium:OP建议可读流实现IReadable而不是具有CanRead属性.使用CanRead,如果流变得不可读,它可以从CanRead返回false.但是使用IReadable,它无法从类型声明中删除IReadable. (5认同)
  • CanRead并不是您需要锁定流的唯一原因.Stream是一种单一资源,如果你以无组织的方式从多个线程中查找它,将会导致很多问题. (3认同)
  • 你能详细说明吗?我不明白为什么CanRead无法在运行时更改. (2认同)

Cra*_*ney 7

他们可能没有使用接口,因为当时没有扩展方法.如果您希望每个流都具有默认的ReadByte方法,则需要使用类.

几个月前我写了一篇关于为什么我不喜欢IO.Stream以及我认为应该做什么的博客文章.从本质上讲,它归结为不是非常类型安全的流.


Ger*_*ald 5

接口可能被过度使用,这将是其中一种情况.我认为目前的设计很棒.流可以在运行时更改功能这一事实意味着IReadable/IWritable/ISeekable不会消除对CanRead,CanWrite和CanSeek的需求,因此除了消除少数存根方法和属性之外,您只会增加复杂性而无法获得实际收益.在派生类中.

就个人而言,我更喜欢流类更易于使用而不是更容易编写,因为您将编写一次并使用它多次.