0

We know Dispose(bool disposing) should be protected or private, what if i need to manually release the unmanage resources? Dispose() from interface IDISPOSIBLE must call Dispose(true) which means release all resource. i want to manually control the release of manage and unmanage resouces.

The official way to implement Dispose is https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose . however sometime i need to manually release the certain resource by use Dispose(false) should this function be public or do i need create another function like DisposeUnManage() for dispose unmanage resource manually?

public void Dispose()
   { 
      Dispose(true);
      GC.SuppressFinalize(this);           
   }

  protected virtual void Dispose(bool disposing)
   {
      if (disposed)
         return; 

      if (disposing) {
         handle.Dispose();
         // Free any other managed objects here.

      }

      disposed = true;
   }
public void Dispose()
   { 
      Dispose(true);
      GC.SuppressFinalize(this);           
   }

public void DisposeUnmanage()
{
Dispose(false);
}

private void Dispose(bool disposing)
   {
      if (disposed)
         return; 

      if (disposing) {
         handle.Dispose();
         // Free any other managed objects here.

      }

      disposed = true;
   }

like this code from TCPStream, i need to use this TCPStream.Dispose(false) method when a TCP client is disconnected. when my TCPServer shutdown i should call TCPStream.Dispose(true).

/// <summary>
        /// Closes the underlying socket
        /// </summary>
        /// <param name="disposing">
        /// If true, the EventArg objects will be disposed instead of being re-added to 
        /// the IO pool. This should NEVER be set to true unless we are shutting down the server!
        /// </param>
        private void Dispose(bool disposeEventArgs = false)
        {
            // Set that the socket is being closed once, and properly
            if (SocketClosed) return;
            SocketClosed = true;

            // If we need to dispose out EventArgs
            if (disposeEventArgs)
            {
                ReadEventArgs.Dispose();
                WriteEventArgs.Dispose();
                DisposedEventArgs = true;
            }
            else
            {
                // Finally, release this stream so we can allow a new connection
                SocketManager.Release(this);
                Released = true;
            }

            // Do a shutdown before you close the socket
            try
            {
                Connection.Shutdown(SocketShutdown.Both);
            }
            catch (Exception) { }
            finally
            {
                // Unregister for vents
                ReadEventArgs.Completed -= IOComplete;
                WriteEventArgs.Completed -= IOComplete;

                // Close the connection
                Connection.Close();
                Connection = null;
            }           

            // Call Disconnect Event
            if (!DisconnectEventCalled && OnDisconnected != null)
            {
                DisconnectEventCalled = true;
                OnDisconnected();
            }
        }
xiaojiuwo
  • 5
  • 2
  • 2
    Make or use an `IDisposable` type only for the unmanaged resources, and pass it in the constructor (dependency injector). The caller can then dispose it and... wait, if the caller is in control of the disposal of unmanaged resources, will that not let your type in an unstable state? I smell [XY problem](http://xyproblem.info/), what is it you really need to solve? – Theraot Oct 06 '19 at 01:24
  • 2
    _"sometime i need to manually release the certain resource by use Dispose(false)"_ -- what does that mean? Passing `false` to `Dispose(bool)` is for the finalizer, i.e. to release _only_ unmanaged resources, since the runtime will take care of dealing with finalizable objects. You shouldn't be calling it at other times. I am skeptical of the need to be able to dispose some subset of your owned objects, but if you must, just make a completely separate public method for client code to call. Maybe you should be writing a cache instead though. – Peter Duniho Oct 06 '19 at 01:41
  • 1
    The idea behind a disposable class is that it wraps/hides the resource from the caller. The caller simply needs to call Dispose when it is done. It should not have to manage it directly like this. – John Wu Oct 06 '19 at 02:59
  • 1
    If you have a need to release certain resources and leave others it can indicate the serious design flaw, in particular problems with responsibilities decomposition. And btw your `Dispose` method is very unsafe - it uses managed objects regardless of how it's called and being triggered from finalizer can lead to significant problems. – Dmytro Mukalov Oct 06 '19 at 06:33

1 Answers1

0

You're clearly abusing the disposable pattern.

Dispose(bool disposing) is meant to be called exactly once when the object is no longer needed and will never be used again. It can be either because someone directly called Dispose() (which calls Dispose(true)), or because the object's finalizer runs (which calls Dispose(false)). Also, as @Dmytro Mukalov pointed out, using managed objects during Dispose(false) is unsafe and can lead to hard to debug issues (but it's only applicable if your object actually has a finalizer).

If you're trying to achieve object pooling, I'd suggest you create and then inject a pooling service into this TCPStream. It would manage the lifetime of pooled objects and would allow Rent and Return operations. Then TCPStream.Dispose() will Return any previously Rented objects and get rid of its own resources, while the actual pooled objects will only be disposed when the pooling service gets disposed (which you can set up to be at TCPServer shutdown). As it stands now, your TCPStream has too many responsibilities, which prohibits you from implementing the disposable pattern correctly.

V0ldek
  • 9,623
  • 1
  • 26
  • 57
  • thanks a lot, would you mind give me a little help with refactoring TCPStream class? How can i contact with you? – xiaojiuwo Oct 07 '19 at 00:49
  • @xiaojiuwo If you need help refactoring, you should post your code to the [Code Review SE](https://codereview.stackexchange.com/). You'll reach a large community of people smarter than me that could help you. – V0ldek Oct 07 '19 at 06:59
  • thx, btw i find another useful code, so i do not need to refactor this. thanks again! – xiaojiuwo Oct 08 '19 at 01:09