C# 正确使用带有 SafeSocketHandle 的 Dispose
C# proper use of Dispose with SafeSocketHandle
我知道 dispose pattern 并想正确处理我的 Socket 资源。
在文档中他们建议使用 SafeHandles, but I'm not sure how exactly this works with System.Net.Socket. I discovered that the Socket class itself includes a SafeSocketHandle,但我不知道如何使用它。我需要处理手柄和插座还是只处理手柄就足够了?我假设在 class 中我只使用句柄进行套接字操作,对吗?
public class MySocket : IDisposable
{
private SafeSocketHandle _handle;
private bool _disposed = false;
public MySocket(AddressFamily addressFamily)
{
Socket s = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
_handle = s.SafeHandle;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
_handle.Dispose();
}
_disposed = true;
}
}
也许有人也能解释为什么要使用 SafeHandles?
我的意思是这还不够吗?:
public class MySocket : IDisposable
{
private Socket _socket;
private bool _disposed = false;
public MySocket(AddressFamily addressFamily)
{
_socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
_socket.Dispose();
}
_disposed = true;
}
}
当您直接管理非托管资源时,您应该使用 SafeHandle
。
对于 Socket
,有一个底层非托管资源,但它由 Socket
class 处理。您无需参与其中——Socket
本身是托管资源,而不是非托管资源。 Socket
有自己的终结器,如果您忘记处置它,它将(可能)释放底层的非托管资源。
所以,在这里你不用担心SafeHandles
。只需实施 IDisposable
并调用 _socket.Dispose()
.
您不需要在此处实现完整的 Dispose 模式,除非您可能有一个派生的 class,它拥有自己的非托管资源。写就够了:
public class MySocket : IDisposable
{
private Socket _socket;
private bool _disposed = false;
public MySocket(AddressFamily addressFamily)
{
_socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
}
public void Dispose()
{
_socket.Dispose();
_disposed = true;
}
}
事实上,许多编码标准要求非托管资源 必须 包装在 SafeHandle
中。如果这样做,则无需实施完整的 Dispose 模式。
如果您需要实现完整的处理模式,您还需要编写终结器。您问题中的代码不会执行此操作。
事实上,dispose 模式鼓励用户走上一条相当危险的道路——在 void Dispose(bool disposing)
方法中编写正确的代码确实非常困难,并且存在大多数用户都没有意识到的陷阱。这就是在 .NET 2.0 中引入 SafeHandle
的原因——运行时对其有特殊支持,从而避免了这些陷阱——但关于 IDisposable
的建议似乎从未更新过。
我知道 dispose pattern 并想正确处理我的 Socket 资源。 在文档中他们建议使用 SafeHandles, but I'm not sure how exactly this works with System.Net.Socket. I discovered that the Socket class itself includes a SafeSocketHandle,但我不知道如何使用它。我需要处理手柄和插座还是只处理手柄就足够了?我假设在 class 中我只使用句柄进行套接字操作,对吗?
public class MySocket : IDisposable
{
private SafeSocketHandle _handle;
private bool _disposed = false;
public MySocket(AddressFamily addressFamily)
{
Socket s = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
_handle = s.SafeHandle;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
_handle.Dispose();
}
_disposed = true;
}
}
也许有人也能解释为什么要使用 SafeHandles? 我的意思是这还不够吗?:
public class MySocket : IDisposable
{
private Socket _socket;
private bool _disposed = false;
public MySocket(AddressFamily addressFamily)
{
_socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
_socket.Dispose();
}
_disposed = true;
}
}
当您直接管理非托管资源时,您应该使用 SafeHandle
。
对于 Socket
,有一个底层非托管资源,但它由 Socket
class 处理。您无需参与其中——Socket
本身是托管资源,而不是非托管资源。 Socket
有自己的终结器,如果您忘记处置它,它将(可能)释放底层的非托管资源。
所以,在这里你不用担心SafeHandles
。只需实施 IDisposable
并调用 _socket.Dispose()
.
您不需要在此处实现完整的 Dispose 模式,除非您可能有一个派生的 class,它拥有自己的非托管资源。写就够了:
public class MySocket : IDisposable
{
private Socket _socket;
private bool _disposed = false;
public MySocket(AddressFamily addressFamily)
{
_socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
}
public void Dispose()
{
_socket.Dispose();
_disposed = true;
}
}
事实上,许多编码标准要求非托管资源 必须 包装在 SafeHandle
中。如果这样做,则无需实施完整的 Dispose 模式。
如果您需要实现完整的处理模式,您还需要编写终结器。您问题中的代码不会执行此操作。
事实上,dispose 模式鼓励用户走上一条相当危险的道路——在 void Dispose(bool disposing)
方法中编写正确的代码确实非常困难,并且存在大多数用户都没有意识到的陷阱。这就是在 .NET 2.0 中引入 SafeHandle
的原因——运行时对其有特殊支持,从而避免了这些陷阱——但关于 IDisposable
的建议似乎从未更新过。