特定情况下的 C# Dispose() 标准

C# Dispose() standard with certain situation

我们知道Dispose(bool disposing)应该是protected或者private的,如果我需要手动释放unmanage资源怎么办?来自接口 IDISPOSIBLE 的 Dispose() 必须调用 Dispose(true),这意味着释放所有资源。我想手动控制manage和unmanage资源的释放。

官方实现 Dispose 的方式是 https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose 。 但是有时我需要通过使用 Dispose(false) 手动释放某些资源,这个函数应该是 public 还是我需要创建另一个函数,如 DisposeUnManage() 来手动处理未管理的资源?

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;
   }

就像 TCPStream 中的这段代码一样,我需要在 TCP 客户端断开连接时使用这种 TCPStream.Dispose(false) 方法。当我的 TCPServer 关闭时,我应该调用 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();
            }
        }

你显然在滥用一次性模式。

Dispose(bool disposing) 意味着当对象不再需要并且永远不会被再次使用时,只调用一次。这可能是因为有人直接调用 Dispose()(调用 Dispose(true)),或者因为对象的终结器运行(调用 Dispose(false))。此外,正如@Dmytro Mukalov 指出的那样,在 Dispose(false) 期间使用托管对象是不安全的,并且可能导致难以调试的问题(但它仅适用于您的对象实际上具有终结器的情况)。

如果您正在尝试实现对象池化,我建议您创建一个池化服务,然后将其注入此 TCPStream。它将管理合并对象的生命周期,并允许 RentReturn 操作。然后 TCPStream.Dispose()Return 任何以前 Rented 的对象并摆脱它自己的资源,而实际的池化对象只会在池服务被处理时被处理(你可以设置在 TCPServer 关闭)。现在看来,你的 TCPStream 职责太多,导致你无法正确实现一次性模式。