使用 try/finally 是内存管理的好习惯吗?
Is using try/finally a good practice for memory management?
我的一位前辈告诉我对所有方法使用 try/ finally
块来清除初始化对象数据。
例如:
var serviceProxy = new NotificationServiceProxy();
try
{
return serviceProxy.GetNotifications(userID, request.Filters, request.FilterProperty, usertypeid);
}
finally
{
serviceProxy = null;
}
这是一个好习惯吗?如果我对我的所有方法都使用 try/ catch
来清除初始化对象数据。
是的,如果你需要处理一个变量。
您不需要清除局部变量。在退出该方法之前,无论如何都会恢复堆栈(这将释放变量使用的堆栈上的 space)并且将局部变量设置为 null
不会释放 space 在堆上(垃圾收集器会这样做)。如果您需要进行一些清理,例如对象处理或关闭文件,请使用 try finally
。
不是在 C# 中,而是使用 using
:
using(var serviceProxy = new NotificationServiceProxy()){
serviceProxy.GetNotifications(userID, request.Filters, request.FilterProperty, usertypeid);
// Do stuff with the service proxy
}
// serviceProxy has now been cleaned up
这是确保 IDisposable
变量得到清理的模式。
对于不是一次性的实例,不需要这样做 - 只需让它们超出范围并将其留给 GC。
如果 NotificationServiceProxy
使用大量资源,您需要确保它已正确完成,然后将其制成一次性的,并始终将其包装在 using
或另一个 class 中还实现了 IDisposable
。如果不是,那么这个 try-finally
模式就是浪费时间。
不,这不是一个好的做法。
您正在手动完成工作,compiler/garbage 收集器将为您完成。这是不必要的时间花费和不必要的代码混乱,您需要在以后删除或维护。
您完全错过了 .Dispose()
服务参考。尽管此 可以 在 finally
块中完成,但 using
块正是为此目的而存在的。
这种做法好不好,要看场景。捕获异常通常很好,这样您就可以优雅地处理意外情况。如果您的程序开发了一些其他方法来处理异常情况,那么 Try/Finally 块应该足够了,因为 Catch 块有一些性能损失。
请查看来自 MSDN 的 Consideration When Using Try Catch 文章。
首先,你不需要清除局部变量(垃圾收集器会为你做),但是,它是安全的:
Object o = new Object();
...
o = null; // safe, but not required
你要做的是清除非托管资源;典型的方法是实现 IDisposable
接口并将相应的实例包装到 using
:
// Providing that serviceProxy implements IDisposable
using (var serviceProxy = new NotificationServiceProxy()) {
return serviceProxy.GetNotifications(
userID,
request.Filters,
request.FilterProperty,
usertypeid);
} // <- here .Net will call serviceProxy.Dispose() and free the resources allocated
有时您必须恢复初始状态,就是这种情况try..finally
设计用于:
Cursor savedCursor = Cursor.Current;
try {
Cursor.Current = Cursors.WaitCursor;
...
}
finally {
// Rain (exception thrown) or shine (no exception), please, restore my cursor
Cursor.Current = savedCursor;
}
在您的特定情况下,我看不到任何要恢复的状态,这就是为什么 try..finally
不是应该使用的模式。但是,serviceProxy
很可能会分配一些 非托管资源 (例如,TCP/IP 端口、连接或类似资源),因此您似乎应该实现 IDisposable
对于 NotificationServiceProxy
class (如果它还没有实现)并将实例包装到 using
.
当您需要 HAS 发生的事情时,无论您的操作是失败还是成功,都可以处理 IDisposable 对象,这很有意义。
try
{
myDisposable.Do();
}
finally
{
myDisposable.Dispose();
}
你有一个内置的机制可以做到这一点:使用
using(IDisposable myDisposable = new Something())
{
myDisposable.Do();
}
现在要好好练习了:
这有点取决于您的错误处理策略和清理需求:
如果我有必须完成的事情,无论操作成功还是失败,我都会在 try finally 块中放置。
如果我有一些只需要错误处理而不需要清理的东西,我会在没有 finally 块的情况下放置 try catch
如果我必须进行某种错误处理,我也会在其中放置一个 catch 块
如果我不想像日志那样进行一些错误处理,然后让异常从该堆栈传播,我也会重新抛出异常。
或上述条件的任何排列..
例如:
try
{
myDisposable.Do();
}
catch(Exception e)
{
Log("Error at something something",e);
throw e;
}
finally
{
myDisposable.Dispose();
}
我个人并没有在每个地方都放置 try catch finally,我希望我的代码中确实包含它们的地方脱颖而出,说明这些操作由于某些已知原因而已知会出错。
我欢迎新的异常,我还不知道并相应地处理它们。
我的一位前辈告诉我对所有方法使用 try/ finally
块来清除初始化对象数据。
例如:
var serviceProxy = new NotificationServiceProxy();
try
{
return serviceProxy.GetNotifications(userID, request.Filters, request.FilterProperty, usertypeid);
}
finally
{
serviceProxy = null;
}
这是一个好习惯吗?如果我对我的所有方法都使用 try/ catch
来清除初始化对象数据。
是的,如果你需要处理一个变量。
您不需要清除局部变量。在退出该方法之前,无论如何都会恢复堆栈(这将释放变量使用的堆栈上的 space)并且将局部变量设置为 null
不会释放 space 在堆上(垃圾收集器会这样做)。如果您需要进行一些清理,例如对象处理或关闭文件,请使用 try finally
。
不是在 C# 中,而是使用 using
:
using(var serviceProxy = new NotificationServiceProxy()){
serviceProxy.GetNotifications(userID, request.Filters, request.FilterProperty, usertypeid);
// Do stuff with the service proxy
}
// serviceProxy has now been cleaned up
这是确保 IDisposable
变量得到清理的模式。
对于不是一次性的实例,不需要这样做 - 只需让它们超出范围并将其留给 GC。
如果 NotificationServiceProxy
使用大量资源,您需要确保它已正确完成,然后将其制成一次性的,并始终将其包装在 using
或另一个 class 中还实现了 IDisposable
。如果不是,那么这个 try-finally
模式就是浪费时间。
不,这不是一个好的做法。
您正在手动完成工作,compiler/garbage 收集器将为您完成。这是不必要的时间花费和不必要的代码混乱,您需要在以后删除或维护。
您完全错过了
.Dispose()
服务参考。尽管此 可以 在finally
块中完成,但using
块正是为此目的而存在的。
这种做法好不好,要看场景。捕获异常通常很好,这样您就可以优雅地处理意外情况。如果您的程序开发了一些其他方法来处理异常情况,那么 Try/Finally 块应该足够了,因为 Catch 块有一些性能损失。
请查看来自 MSDN 的 Consideration When Using Try Catch 文章。
首先,你不需要清除局部变量(垃圾收集器会为你做),但是,它是安全的:
Object o = new Object();
...
o = null; // safe, but not required
你要做的是清除非托管资源;典型的方法是实现 IDisposable
接口并将相应的实例包装到 using
:
// Providing that serviceProxy implements IDisposable
using (var serviceProxy = new NotificationServiceProxy()) {
return serviceProxy.GetNotifications(
userID,
request.Filters,
request.FilterProperty,
usertypeid);
} // <- here .Net will call serviceProxy.Dispose() and free the resources allocated
有时您必须恢复初始状态,就是这种情况try..finally
设计用于:
Cursor savedCursor = Cursor.Current;
try {
Cursor.Current = Cursors.WaitCursor;
...
}
finally {
// Rain (exception thrown) or shine (no exception), please, restore my cursor
Cursor.Current = savedCursor;
}
在您的特定情况下,我看不到任何要恢复的状态,这就是为什么 try..finally
不是应该使用的模式。但是,serviceProxy
很可能会分配一些 非托管资源 (例如,TCP/IP 端口、连接或类似资源),因此您似乎应该实现 IDisposable
对于 NotificationServiceProxy
class (如果它还没有实现)并将实例包装到 using
.
当您需要 HAS 发生的事情时,无论您的操作是失败还是成功,都可以处理 IDisposable 对象,这很有意义。
try
{
myDisposable.Do();
}
finally
{
myDisposable.Dispose();
}
你有一个内置的机制可以做到这一点:使用
using(IDisposable myDisposable = new Something())
{
myDisposable.Do();
}
现在要好好练习了:
这有点取决于您的错误处理策略和清理需求:
如果我有必须完成的事情,无论操作成功还是失败,我都会在 try finally 块中放置。
如果我有一些只需要错误处理而不需要清理的东西,我会在没有 finally 块的情况下放置 try catch
如果我必须进行某种错误处理,我也会在其中放置一个 catch 块
如果我不想像日志那样进行一些错误处理,然后让异常从该堆栈传播,我也会重新抛出异常。
或上述条件的任何排列..
例如:
try
{
myDisposable.Do();
}
catch(Exception e)
{
Log("Error at something something",e);
throw e;
}
finally
{
myDisposable.Dispose();
}
我个人并没有在每个地方都放置 try catch finally,我希望我的代码中确实包含它们的地方脱颖而出,说明这些操作由于某些已知原因而已知会出错。
我欢迎新的异常,我还不知道并相应地处理它们。