try/catch + using, right syntax
哪一个:
1 2 3 4 5 6 7 8 9 10 11
| using (var myObject = new MyClass ())
{
try
{
// something here...
}
catch(Exception ex )
{
// Handle exception
}
} |
或
1 2 3 4 5 6 7 8 9 10 11
| try
{
using (var myObject = new MyClass ())
{
// something here...
}
}
catch(Exception ex )
{
// Handle exception
} |
- 注意:除了日志记录或包装异常之外,应该注意只捕获可以实际处理(更正)的异常。
- 请记住,根据这里的提示,using语句的最后一个}也可能引发异常。
- 如果使用第一块代码,调试器(在VS中)将不会调用Dispose方法。因为using语句本身可以引发异常,所以它可以帮助我使用第二个块来确保隐含的finally调用Dispose方法。
我更喜欢第二个。也可以捕获与对象创建相关的错误。
- 我不同意这个建议。如果您希望创建的对象抛出一个错误,那么对该异常的任何处理都必须在外部进行。如果有关于处理应该去哪里的问题,那么预期的异常必须是其他东西,除非您提倡捕获任何可能或不可能预期的随机异常,这是一个经典的反模式(在进程或线程的未处理异常处理程序之外)。
- @杰弗里:我描述的方法对我很有帮助,而且我已经做了很长时间了。没有人说过期望对象创建失败。但是,通过包装一个可能在try块中失败的操作,它允许您在失败时弹出一条错误消息,程序现在能够恢复并通知用户。
- 您的回答是正确的,但继续建议尝试/捕获必须始终存在(立即)。
- 我认为第一个也有优点,考虑一个数据库事务using( DBConnection conn = DBFactory.getConnection()),如果发生异常,它需要回滚。在我看来,他们都有自己的位置。
- @在这种情况下,最好总是在using退出时回滚事务,除非是显式提交。
- 这还将捕获与对象处理相关的错误。
由于using块只是try/finally(msdn)的语法简化,因此我个人会使用以下方法,尽管我怀疑它与您的第二个选项明显不同:
1 2 3 4 5 6 7 8 9
| MyClass myObject = null;
try {
myObject = new MyClass ();
//important stuff
} catch (Exception ex ) {
//handle exception
} finally {
if(myObject is IDisposable ) myObject .Dispose();
} |
- 为什么您认为添加finally块比using语句更可取?
- 添加一个处理IDisposable对象的finally块就是using语句所做的。就我个人而言,我喜欢这个,而不是嵌入的using块,因为我认为它更清楚地说明了所有事情都发生在什么地方,并且都处于同一"水平"。我也喜欢这个多个嵌入的using块…但这都是我的偏好。
- 如果您实现了许多异常处理,那么您一定非常喜欢打字!"使用"这个关键词已经存在一段时间了,我很清楚它的含义。使用它有助于将混乱的数量保持在最低限度,从而使我的其余代码更加清晰。
- 这是不正确的。对象必须在try语句外实例化,以便在finally语句内释放;否则,它将引发编译器错误:"使用未分配的局部变量'myObject'"
- @Stevekonves,我想你在技术上是正确的,第一行应该是var myObject=null;,尽管我不会认为任何伪代码的崩溃…
- 从技术上讲,这也不会编译。Cannot assign null to implicitly-typed local variable,但我知道你的意思,而且我个人更喜欢这样嵌套一个使用块。
- @Chezy525你为什么要在《最后》中使用排版?在.NET 3.5或更高版本中确实需要这样做吗?以前?
- @Chezy525是否可以最终引发另一个类型转换异常?
- @martinmeeser,我想您是否需要在finally块中进行类型转换取决于您如何设置变量(作为var或其他不需要作为IDisposable的基类,这是必需的)。但是,我相信您可能是正确的,因为代码可能会在finally块中抛出一个类型转换异常(现在应该修复它)。
- finally { myObject?.Dispose() }与finally { if(myObject == null) myObject.Dispose() }相同,您不需要再次安全地转换变量,因为您已经知道它是从myclass实例化的。更便宜的是空支票。
这要看情况而定。如果您正在使用Windows通信基础(WCF),如果EDCOX1 OR 2语句中的代理处于异常状态,则EDCOX1 OR 1将不能正常工作,即处理此代理将导致另一个异常。
就个人而言,我相信最小处理方法,即只处理您在执行时知道的异常。换句话说,如果您知道using中变量的初始化可能会引发一个特定的异常,那么我用try-catch将其包装起来。同样地,如果在using体中可能发生一些与using中的变量没有直接关系的事情,那么我用另一个try来包装它,以解决这个特殊的例外情况。我很少在我的catch中使用Exception。
但我确实喜欢IDisposable和using,尽管我可能有偏见。
如果catch语句需要访问using语句中声明的变量,那么只有inside选项。
如果catch语句在释放前需要在using中引用的对象,则只有inside选项。
如果catch语句执行的操作持续时间未知,例如向用户显示消息,并且您希望在执行该操作之前释放资源,那么outside是您的最佳选择。
每当我有一个与此类似的scenerio时,try-catch块通常位于调用堆栈上方的另一个方法中。对于一个方法来说,知道如何处理在它内部发生的异常是不典型的。
所以我一般的建议是在外面。
1 2 3 4 5 6 7 8 9 10 11
| private void saveButton_Click(object sender, EventArgs args)
{
try
{
SaveFile(myFile); // The using statement will appear somewhere in here.
}
catch (IOException ex)
{
MessageBox.Show(ex.Message);
}
} |
两者都是有效的语法。它实际上可以归结为您想要做的:如果您想要捕获与创建/处理对象相关的错误,请使用第二个。如果没有,请使用第一个。
这里有一件重要的事情我将在这里指出:第一件事情不会捕获调用MyClass构造函数所产生的任何异常。
如果您在using()块中初始化的对象可能引发任何异常,那么您应该使用第二种语法,否则这两种语法都同样有效。
在我的场景中,我必须打开一个文件,并在我在using()块中初始化的对象的构造函数中传递filepath,如果filepath错误/为空,它可能引发异常。所以在本例中,第二种语法是有意义的。
我的样本代码:
1 2 3 4 5 6 7 8 9 10 11
| try
{
using (var obj = new MyClass ("fileName.extension"))
{
}
}
catch(Exception ex )
{
//Take actions according to the exception.
} |