C# 在不使用的情况下处理异常资源
C# Dispose resources on exceptions without using
我正在编写一个包含套接字操作的 class 库。我不想依赖消费者在完成后或抛出异常时处理资源。
通常我会使用 "using" 语句,但这在本地范围之外不起作用。在我的例子中,我有一个 class 并在许多 public 方法中使用套接字。连接结束时处理 Socket 很容易,但是在没有 "using" 块的情况下抛出异常时如何处理它?
这是我想出的:
基本上,我用 try catch 块封装了用户可以访问的每个方法。如果发生异常,我会在向用户抛出异常之前处理资源。
但我想知道是否有更好的选择。如果我对图书馆消费者隐藏这个自动处理是不好的。
public class Foo
{
Socket _socket;
public void method1()
{
try
{
// some work with _socket
}
catch
{
_socket.Dispose();
throw;
}
}
}
从错的地方说起
例如,您应该在构造函数中创建套接字并在析构函数中处理它,否则在像方法 1 中那样捕获到第一个异常之后,您将拥有一个可以继续使用的已处理对象的引用...
public class Foo
{
private Socket _socket { get; }
public Foo()
{
_socket = new Socket();
}
~Foo()
{
_socket.Dispose();
}
public void method1()
{
try
{
// some work with _socket
}
catch
{
throw;
}
}
}
做正确的事
理想情况下,您应该将 Foo 标记为实现 IDispose 并在 Dispose 方法中释放套接字。
它将更加干净和健壮。
所以你可以通过 using 模式使用 Foo,或者你可以调用 Foo.Dispose
.
public class Foo : IDisposable
{
private Socket _socket { get; }
private bool IsDisposed;
public Foo()
{
_socket = new Socket();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if ( IsDisposed ) return;
if ( disposing )
{
if ( _socket != null )
try
{
_socket.Dispose();
_socket = null;
}
catch ( Exception ex )
{
// Show message or do nothing
}
}
IsDisposed = true;
}
}
您有 2 个备选方案:
使用标准 IDisposable
实现
public class Foo : IDisposable {
Socket _socket;
...
public void method1() {
// working with _socket
}
protected virtual void Dispose(bool disposing) {
if (disposing) {
if (_socket != null) {
_socket.Dispose();
_socket = null;
}
}
}
public void Dispose() {
Dispose(true);
}
}
或者把_socket
变成局部变量:
public void method1() {
using (Socket _socket = new Socket(...)) {
// working with _socket
}
}
我正在编写一个包含套接字操作的 class 库。我不想依赖消费者在完成后或抛出异常时处理资源。
通常我会使用 "using" 语句,但这在本地范围之外不起作用。在我的例子中,我有一个 class 并在许多 public 方法中使用套接字。连接结束时处理 Socket 很容易,但是在没有 "using" 块的情况下抛出异常时如何处理它?
这是我想出的: 基本上,我用 try catch 块封装了用户可以访问的每个方法。如果发生异常,我会在向用户抛出异常之前处理资源。
但我想知道是否有更好的选择。如果我对图书馆消费者隐藏这个自动处理是不好的。
public class Foo
{
Socket _socket;
public void method1()
{
try
{
// some work with _socket
}
catch
{
_socket.Dispose();
throw;
}
}
}
从错的地方说起
例如,您应该在构造函数中创建套接字并在析构函数中处理它,否则在像方法 1 中那样捕获到第一个异常之后,您将拥有一个可以继续使用的已处理对象的引用...
public class Foo
{
private Socket _socket { get; }
public Foo()
{
_socket = new Socket();
}
~Foo()
{
_socket.Dispose();
}
public void method1()
{
try
{
// some work with _socket
}
catch
{
throw;
}
}
}
做正确的事
理想情况下,您应该将 Foo 标记为实现 IDispose 并在 Dispose 方法中释放套接字。
它将更加干净和健壮。
所以你可以通过 using 模式使用 Foo,或者你可以调用 Foo.Dispose
.
public class Foo : IDisposable
{
private Socket _socket { get; }
private bool IsDisposed;
public Foo()
{
_socket = new Socket();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if ( IsDisposed ) return;
if ( disposing )
{
if ( _socket != null )
try
{
_socket.Dispose();
_socket = null;
}
catch ( Exception ex )
{
// Show message or do nothing
}
}
IsDisposed = true;
}
}
您有 2 个备选方案:
使用标准 IDisposable
实现
public class Foo : IDisposable {
Socket _socket;
...
public void method1() {
// working with _socket
}
protected virtual void Dispose(bool disposing) {
if (disposing) {
if (_socket != null) {
_socket.Dispose();
_socket = null;
}
}
}
public void Dispose() {
Dispose(true);
}
}
或者把_socket
变成局部变量:
public void method1() {
using (Socket _socket = new Socket(...)) {
// working with _socket
}
}