Why calling Dispose() on BinaryReader results in compile error?

前端 未结 3 1443
时光取名叫无心
时光取名叫无心 2021-01-15 03:41

I have the following class which uses BinaryReader internally and implements IDisposable.

class DisposableClass : IDisposable
    {
        private BinaryReader r         


        
3条回答
  •  一整个雨季
    2021-01-15 04:37

    Expanding on my comments here, the BinaryReader class does not properly implement the Dispose pattern.

    Looking at this class in Reflector, it looks like this (for .NET 3.5):

    public class BinaryReader : IDisposable
    {
        public virtual void Close()
        {
           this.Dispose(true);
        }
        protected virtual void Dispose(bool disposing)
        {
           if (disposing)
           {
              Stream stream = this.m_stream;
              this.m_stream = null;
              if (stream != null)
              {
                 stream.Close();
              }
           }
           this.m_stream = null;
           this.m_buffer = null;
           this.m_decoder = null;
           this.m_charBytes = null;
           this.m_singleChar = null;
           this.m_charBuffer = null;
       }
       void IDisposable.Dispose()
       {
          this.Dispose(true);
       }
    }
    

    The problem here is that by making IDisposable.Dispose() an explicit interface implementaiton it forces a developer to call Close() instead of Dispose().

    In this context, we have a case of imbalanced semantics. There was never a call to "Open" the reader so it is not intuitive to "Close" the reader.

    Going one step further, in order to call Dispose() you must then explicitly cast to IDisposable, which is not something you ordinarily need to do. You do have the option of calling Dispose(bool) directly, but how do you know what the boolean parameter should be?

    To properly follow the pattern, it should have been implmented as:

    public class BinaryReader : IDisposable
    {
        public virtual void Close()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
           if (disposing)
           {
              Stream stream = this.m_stream;
              this.m_stream = null;
              if (stream != null)
              {
                 stream.Close();
              }
           }
           this.m_stream = null;
           this.m_buffer = null;
           this.m_decoder = null;
           this.m_charBytes = null;
           this.m_singleChar = null;
           this.m_charBuffer = null;
       }
       public void Dispose()
       {
          this.Close();
       }
    }
    

    This would allow you to call either Close() or Dispose(), in which case either call continues to result in calling Dispose(true). (This is the same flow as the actual implementation by calling Close() or ((IDisposable)reader).Dispose()).

    Fortunately (or unfortunately, depending on which way you choose to look at it) because BinaryReader does implement the IDisposable interface it is allowed in a using statement:

    using (BinaryReader reader = new BinaryReader(...))
    {
    }
    

提交回复
热议问题