尝试/捕获+使用正确的语法


189

哪一个:

using (var myObject = new MyClass())
{
   try
   {
      // something here...
   }
   catch(Exception ex)
   {
      // Handle exception
   }
}

要么

try
{
   using (var myObject = new MyClass())
   {
      // something here...
   }
}
catch(Exception ex)
{
   // Handle exception
}

7
仅需注意:请注意仅捕获可以记录(包装)的异常,这些异常可以实际处理(更正)。
约翰·桑德斯

1
请记住,正如此处所提醒}的,using语句的最后也可能引发异常。
朱利奥·卡钦

1
如果您使用第一个代码块,则调试器(在VS中)将不会调用dispose方法。因为using语句本身可以引发异常,所以它有助于我使用第二个块来确保隐式finally调用了dispose方法。
ShooShoSha

Answers:


98

我喜欢第二个。也可以捕获与对象创建有关的错误。


11
我不同意这个建议。如果期望对象创建会引发错误,那么对该异常的任何处理都必须在外部进行。如果对处理应该去哪里有疑问,那么预期的异常必须是其他东西—除非您提倡捕获可能会或可能不会预期的任何随机异常,这是一种经典的反模式(在进程或线程的未处理异常处理程序)。
杰弗里·惠特里奇

1
@Jeffrey:我描述的方法对我很有帮助,并且我已经做了很长时间了。没有人说期望对象创建失败。但是,通过将可能失败的操作包装在一个try块中,该操作使您可以在发生某些故障时弹出错误消息,该程序现在可以恢复并通知用户。
乔纳森·伍德

你的答案是正确的,但仍然是在try / catch语句的建议具有在任何时候都在那里(立即)。
汉克·霍尔特曼

17
我认为第一个也是有好处的,考虑一个DB事务using( DBConnection conn = DBFactory.getConnection()),如果发生异常,则该事务需要回滚。在我看来,两者都有自己的位置。
wfoster 2011年

1
这也将捕获与处置对象有关的错误。
艾哈迈德·易卜拉欣

39

由于using块只是try / finally(MSDN)的语法简化,因此我个人将采用以下内容,尽管我怀疑它与您的第二种选择有很大不同:

MyClass myObject = null;
try {
  myObject = new MyClass();
  //important stuff
} catch (Exception ex) {
  //handle exception
} finally {
  if(myObject is IDisposable) myObject.Dispose();
}

4
为什么您认为添加一个语句比声明finally更可取using
科迪·格雷

10
语句将添加一个finally放置IDisposable对象的块using。就我个人而言,我喜欢它而不是嵌入式using块,因为我认为它更清楚地说明了所有事情的发生位置,并且它们都处于同一“级别”。我还不仅仅喜欢几个嵌入式using块...但这全都是我的偏爱。
chezy525 2011年

8
如果您实现了很多异常处理,那么您必须真正享受打字的乐趣!这个“ using”关键字已经存在了一段时间,这对我来说很清楚。并使用它可以使混乱的数量降至最低,从而使我的其余代码更加清晰。
乔纳森·伍德

2
这是不正确的。必须在try语句外实例化该对象,才能将其放置在finally语句内;否则,它将引发编译器错误:“使用未分配的局部变量'myObject'”
Steve Konves 2012年

3
从技术上讲,也不会编译。Cannot assign null to implicitly-typed local variable;)但是我知道您的意思,并且个人比较喜欢嵌套using块。
康奈尔

20

这取决于。如果您使用的是Windows Communication Foundation(WCF),using(...) { try... }则in using语句中的代理处于异常状态将无法正常工作,即,处置此代理将导致另一个异常。

就我个人而言,我相信使用最少的处理方法,即仅处理您在执行时意识到的异常。换句话说,如果您知道in中的变量的初始化using可能会引发特定的异常,请使用进行包装try-catch。同样,如果using体内可能发生某些事情,而这与中的变量没有直接关系using,则try针对该特定异常,我将其包裹起来。我很少ExceptioncatchES中使用。

但是我确实喜欢IDisposableusing尽管如此,我还是有偏见。


19

如果您的catch语句需要访问using语句中声明的变量,那么inside是您唯一的选择。

如果您的catch语句在处理之前需要使用中引用的对象,则内部是您唯一的选择。

如果您的catch语句执行的持续时间未知,例如向用户显示一条消息,并且您希望在这种情况发生之前就处理掉资源,那么外部是您的最佳选择。

每当我有一个与此相似的场景时,try-catch块通常会以与使用相比更远的调用堆栈采用另一种方法。这样的方法通常并不知道如何处理其中发生的异常。

因此,我的一般建议是在外面,在外面。

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

10

两者都是有效的语法。这实际上取决于您要执行的操作:如果要捕获与创建/处置对象有关的错误,请使用第二个。如果不是,请使用第一个。


8

我在这里要指出一件事:第一个不会捕获任何由于调用MyClass构造函数而引起的异常。


3

从C#8.0开始,我更喜欢这样使用第二个

public class Person : IDisposable
{
    public Person()
    {
        int a = 0;
        int b = Id / a;
    }
    public int Id { get; set; }

    public void Dispose()
    {
    }
}

然后

static void Main(string[] args)
    {

        try
        {
            using var person = new Person();
        }
        catch (Exception ex) when
        (ex.TargetSite.DeclaringType.Name == nameof(Person) &&
        ex.TargetSite.MemberType == System.Reflection.MemberTypes.Constructor)
        {
            Debug.Write("Error Constructor Person");
        }
        catch (Exception ex) when
       (ex.TargetSite.DeclaringType.Name == nameof(Person) &&
       ex.TargetSite.MemberType != System.Reflection.MemberTypes.Constructor)
        {
            Debug.Write("Error Person");
        }
        catch (Exception ex)
        {
            Debug.Write(ex.Message);
        }
        finally
        {
            Debug.Write("finally");
        }
    }

1

如果要在Using()块中初始化的对象可能引发任何异常,则应采用第二种语法,否则两者都同样有效。

在我的场景中,我必须打开一个文件,并在正在使用Using()块初始化的对象的构造函数中传递filePath,如果filePath错误/为空,则可能会引发异常。因此,在这种情况下,第二种语法才有意义。

我的示例代码:-

try
{
    using (var obj= new MyClass("fileName.extension"))
    {

    }
}
catch(Exception ex)
{
     //Take actions according to the exception.
}

1

C#8.0开始,您可以using在某些情况下简化语句以摆脱嵌套块,然后将其仅应用于封闭块。

因此,您的两个示例可以简化为:

using var myObject = new MyClass();
try
{
   // something here...
}
catch(Exception ex)
{
   // Handle exception
}

和:

try
{
   using var myObject = new MyClass();
   // something here...
}
catch(Exception ex)
{
   // Handle exception
}

两者都很清楚。然后将这两者之间的选择减少到您希望对象范围是什么,要处理实例化错误的时间以及要处置它的时间。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.