【问题标题】:try/catch + using, right syntaxtry/catch + using,正确的语法
【发布时间】:2011-06-03 04:38:27
【问题描述】:

哪一个:

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
}

【问题讨论】:

  • 请注意:应该注意只捕获实际上可以处理(更正)的异常,日志记录或包装除外。
  • 请记住,using 语句的最后一个} 也可能引发异常as reminded here
  • TIL 如果您使用第一个代码块,调试器(在 VS 中)将不会调用 dispose 方法。因为 using 语句本身可以抛出异常,所以它帮助我使用第二块来确保隐含的 finally 调用了 dispose 方法。

标签: c# try-catch using-statement


【解决方案1】:

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

【讨论】:

  • 我不同意这个建议。如果您希望对象创建会引发错误,那么对该异常的任何处理必须进行。如果有关于处理应该去哪里的问题,那么预期的异常肯定是别的东西——除非你主张捕获任何可能或可能没有预料到的随机异常,这是一个经典的反模式(在进程或线程的未处理异常处理程序)。
  • @Jeffrey:我描述的方法对我很有帮助,而且我已经这样做了很长时间。没有人说过 expecting 对象创建失败。但是,通过将可能可能失败的操作包装在try 块中,如果出现故障,您可以弹出错误消息,程序现在可以恢复并通知用户。跨度>
  • 我认为第一个也有优点,考虑一个数据库事务using( DBConnection conn = DBFactory.getConnection()),如果发生异常,需要回滚它。在我看来,两者都有自己的位置。
  • 这也将捕获与对象的处置相关的错误。
  • @JasonC:新语法只不过是语法糖,只是使用当前代码块来确定范围。它不会使这个问题变得毫无意义。您仍然可以控制该范围。
【解决方案2】:

由于 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();
    }
}

【讨论】:

  • 为什么你认为添加finally 块比using 语句更可取?
  • 添加一个处理 IDisposable 对象的finally 块是using 语句的作用。就个人而言,我喜欢这个而不是嵌入的 using 块,因为我认为它更清楚地说明了一切发生的位置,并且都在同一个“级别”上。我也喜欢这个而不是几个嵌入式 using 块......但这只是我的偏好。
  • 如果你实现了很多异常处理,你一定非常喜欢打字! “使用”关键字已经存在了一段时间,它的含义对我来说很清楚。使用它可以将杂乱的数量降至最低,从而使我的其余代码更清晰。
  • 这是不正确的。该对象必须在try 语句之外实例化,才能在finally 语句中进行处理;否则会抛出编译器错误:“Use of unassigned local variable 'myObject'”
  • 从技术上讲,这也不会编译。 Cannot assign null to implicitly-typed local variable ;) 但我知道你的意思,我个人更喜欢这个而不是嵌套 using 块。
【解决方案3】:

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

如果你的 catch 语句需要在 using 中引用的对象在被释放之前,那么 inside 是你唯一的选择。

如果您的 catch 语句执行一个持续时间未知的操作,例如向用户显示一条消息,并且您希望在此之前处置您的资源,那么外部是您的最佳选择。

每当我遇到与此类似的场景时,try-catch 块通常使用不同的方法,在调用堆栈中从 using 开始。一个方法知道如何处理它内部发生的异常是不典型的。

所以我的一般建议是在外面——在外面。

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

【讨论】:

    【解决方案4】:

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

    就我个人而言,我相信最少的处理方法,即只处理您在执行时知道的异常。换句话说,如果你知道using 中变量的初始化可能会抛出一个特定的异常,我用try-catch 包装它。同样,如果在using 正文中可能发生某些事情,这与using 中的变量没有直接关系,那么我将它与另一个try 包装起来以处理该特定异常。我很少在catches 中使用Exception

    但我确实喜欢IDisposableusing,所以我可能有偏见。

    【讨论】:

      【解决方案5】:

      两者都是有效的语法。它真的归结为您想要做的事情:如果您想捕获与创建/处置对象相关的错误,请使用第二个。如果没有,请使用第一个。

      【讨论】:

        【解决方案6】:

        我要在这里指出一件重要的事情:第一件事将不会捕获因调用 MyClass 构造函数而产生的任何异常。

        【讨论】:

          【解决方案7】:

          C# 8.0 on开始,您可以在某些条件下简化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
          }
          

          两者都很清楚;然后将两者之间的选择减少为您希望对象的范围是什么、您要在哪里处理实例化错误以及何时处理它。

          【讨论】:

          • 这是新的最佳答案
          【解决方案8】:

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

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

          我的示例代码:-

          try
          {
              using (var obj= new MyClass("fileName.extension"))
              {
          
              }
          }
          catch(Exception ex)
          {
               //Take actions according to the exception.
          }
          

          【讨论】:

            【解决方案9】:

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

            【讨论】:

            • 你为什么说来自 C#8.0 ?
            猜你喜欢
            • 2011-09-17
            • 2014-06-18
            • 2017-11-23
            • 1970-01-01
            • 2014-09-30
            • 1970-01-01
            相关资源
            最近更新 更多