在try-catch块中使用块作为IDisposable是否有任何问题

本文关键字:是否 IDisposable 任何 问题 try-catch | 更新日期: 2023-09-27 18:27:15


MSDN建议将实现IDisposable的类的任何实例化放入using块中。或者,如果它在try-catch块内被实例化,则Finally中的Dispose

像这样在try-catch块中使用using块有什么问题吗?

try
{
    using (Foo bar = new Foo())
    {
       bar.doStuff();
    }
}
catch (Exception e)
{
    //vomit e
}

当然,我可以在Finally块中调用Dispose,但我是编程新手,我只是想知道这样做是否切实可行,或者是否有人会打我的后脑勺,对我大喊我是Doing-It-Wrong™

或者更确切地说,我更感兴趣的是知道如果是这样,为什么会出错。

在try-catch块中使用块作为IDisposable是否有任何问题

不,看起来很好。您的bar实例将在您进入catch块之前被丢弃。

这是…卷筒。。。绝对好。

唯一的问题是,您不应该使用catch (Exception),而是捕捉您感兴趣的特定错误(即使这只是一个示例),但这与using无关。事实上,将using放在try块之外的唯一原因是,您希望继续对bar执行与失败代码无关的操作——否则,保持尽可能小的范围通常是个好主意。

还好,但您失去了对可能导致异常的对象的访问权限
捕获一般异常不被认为是的好做法

Foo bar = null;
try
{
    bar = new Foo();
    bar.doStuff();
}
catch (IndexOutOfRangeException e)
{
    //vomit e
    Debug.WriteLine(e.msg);
    if(bar == null) 
       Debug.WriteLine("bar = new Foo() failed ");
    else 
       Debug.WriteLine("bar fail ID = " + bar.ID);
}
catch (Exception e)
{
    // ...
    // unless you are going to handle it gracefully you should rethrow it
}
finally 
{
    if(bar != null) bar.Dispose();
}

您的示例代码是多余的。Using()文件规定:

形式的使用声明

using (ResourceType resource = expression) 

语句对应于两个可能的展开式之一。当ResourceType是值类型时,扩展为

{
   ResourceType resource = expression;
   try {
      statement;
   }
   finally {
      ((IDisposable)resource).Dispose();
   }
}

否则,当ResourceType是引用类型时,扩展为

{
   ResourceType resource = expression;
   try {
      statement;
   }
   finally {
      if (resource != null) ((IDisposable)resource).Dispose();
   }
}

在任一扩展中,嵌入语句中的资源变量都是只读的。

你的代码最终会看起来像:

try
{
    Foo bar = new Foo()
    try
    {
       bar.doStuff();
    }
    finally 
    {
       if (bar != null) ((IDisposable)bar).Dispose();
    }
}
catch (Exception e)
{
    //vomit e
}

两个try语句没有真正的理由。这不是错误的代码,只是在多个try语句的上下文中是多余的。您的问题似乎是关于对象的Disposing。在这种情况下,它是多余的。如果您还担心对象构造函数抛出异常,那么显然需要这样做。

在这样的try-catch块中使用using块有什么问题吗?

不,我一直在写你的例子。

当然,我可以在Finally块中调用Dispose,

在某种程度上,构造函数必须在try/catch之外调用,否则当您到达最终块时,变量将超出范围

有效:

var foo = new bar();
try
{
}
finally
{
  foo.Dispose();
}

无效:

try
{
  var foo = new bar();
}
finally
{
  foo.Dispose();
}

不,这很好,但如果您想在catch期间访问bar,则需要一个内部try catch:

try
{
    using (Foo bar = new Foo())
    {
      try
      {
        bar.doStuff();
      }
      catch (Exception e)
      {
        //vomit e, with bar available.
      }
    }
}
catch (Exception e)
{
    //vomit e, relating to a problem during creation of Foo.
}

或者,正如评论中所建议的,将内部块因素化为一种新方法。