【问题标题】:How do I dispose an IDisposable object if the using statement throws an exception?如果 using 语句引发异常,如何处置 IDisposable 对象?
【发布时间】:2009-07-07 08:38:28
【问题描述】:

如果ExecuteReader 抛出异常,我如何确保在以下代码sn-p 中处理IDataReader

using (IDataReader rdr = cmd.ExecuteReader())
{
    // use it
}

using 语法糖不调用 Dispose 对我来说是有道理的(因为没有实例可以调用它)。但是,如何确定通常由实现 IDisposable 的类分配的稀缺资源将被释放?

【问题讨论】:

  • 如果 ExecuteReader 抛出异常,IDataReader 为空,不需要处理。 ExecuteReader 内部的非托管资源需要清理,应该在自己的 finally 块中处理。

标签: c# exception dispose idisposable


【解决方案1】:

如果在您的示例中 ExecuteReader 抛出异常,它永远不会返回任何内容。然后由 ExecuteReader 的实现来处理在异常之前创建的任何内容。

【讨论】:

  • 对,所以如果抛出异常,清理就成了异常抛出者的责任?
  • @jpoh - 它必须;调用者没有任何对象可以尝试清理。在最坏的情况下,终结器会启动。
【解决方案2】:

如果对象的构造函数运行失败,则说明您没有需要处置的对象。

如果您正在编写一个可能引发异常的构造函数,您最好确保使用 using 或 try-catch 块清理您需要的任何内容。

在您的 IDataReader 示例中,如果 cmd.ExecuteReader() 方法调用失败,只需处理命令对象就足够了。

【讨论】:

  • 为了澄清马特所说的,在一次性类的构造函数中使用 using / try catch 让它正确处理自己的内部资源。我更倾向于 try catch,因为资源可能是类级别的资源,而不仅仅是构造函数级别。如果是,那么使用更合适。
【解决方案3】:

如何将在构造函数之外进行初始化的代码移到单独的函数中。本质上,您将拥有

using (var tc = new TestClass())
{
    tc.Initialize();  // setup the object. acquire expensive resources here, etc.

    ..more code ..
}

【讨论】:

  • 这不是必须的。同样,如果构造函数抛出,则没有什么可清理的。
【解决方案4】:

我认为using语句被翻译成类似于:

try
{
}
finally
{
    disposableUsedObject.Dispose();
}

所以,我认为在正常情况下,应该调用 Dispose ?

另外,您不应该在构造函数中抛出异常,因为用户不会期望在实例化对象时会抛出异常。 我会将可能引发异常的初始化逻辑移到另一个必须在实例化对象后调用的方法(Initialize)。

【讨论】:

  • 但是如果构造函数抛出异常,就没有对象可以dispose了?
  • 你不应该在构造函数中抛出异常,因为这有点出乎意料。您的类的用户不希望在实例化对象时/在构造函数中引发异常。 :) 我认为最好移动初始化逻辑(可以将异常转移到另一个方法(初始化,或类似的东西)
  • 抱歉,我的人为示例似乎使这个问题令人困惑。我将编辑问题,使其更清晰。
  • ck 是正确的。我使用简单的控制台应用程序对此进行了测试,并且当构造函数抛出错误时不会调用 dispose。
  • @Jimmy:Dispose 不会被调用,因为没有要 Dispose 的对象!
猜你喜欢
  • 2016-10-24
  • 1970-01-01
  • 2012-01-08
  • 2010-11-05
  • 2011-09-15
  • 1970-01-01
  • 1970-01-01
  • 2013-10-14
  • 1970-01-01
相关资源
最近更新 更多