使用语句不能正常工作

时间:2014-09-24 14:13:30

标签: c# .net exception using using-statement

我的名为S的类看起来像这样:

public class S : IDisposable
{
    public void Dispose()
    {
        // some code
    }

    public void f()
    {
        throw new Exception("exception");
    }
}

当我使用using语句时,f()方法不会调用s.Dispose()方法。我认为它应该调用Dispose方法,即使发生异常。这就是我在MSDN中读到的内容:" using语句确保即使在对象"上调用方法时发生异常也会调用Dispose。我错过了什么吗?

using (S s = new S())
{
    s.f();
}

调用s.f()结束我的程序而不处理我的对象。我想我不必使用try / catch,因为using语句应该为我做。

3 个答案:

答案 0 :(得分:5)

  

我错过了什么吗?

using语句将转换为try ... finally语句。

根据try ... finally C# reference

  

在处理的异常中,保证运行关联的 finally 块。但是,如果未处理异常,则 finally 块的执行取决于触发异常展开操作的方式。反过来,这取决于您的计算机的设置方式。

所以是的,你遗漏了一些东西:finally块(以及Dispose语句中对using的调用) 保证在任何情况下,包括在你的情况下,都是在未经处理的例外情况下开火。

该页继续建议:

  

通常,当未处理的异常结束应用程序时,无论 finally 块是否运行都不重要。但是,如果您在 finally 块中有语句,即使在这种情况下也必须运行,一种解决方案是将 catch 块添加到 try-finally < / strong>声明。或者,您可以捕获可能在调用堆栈上方的 try-finally 语句的 try 块中抛出的异常。也就是说,您可以在调用包含 try-finally 语句的方法的方法中,或在调用该方法的方法中,或在调用堆栈的任何方法中捕获异常。如果未捕获异常,则执行 finally 块取决于操作系统是否选择触发异常展开操作。

如果我能在C#规范中找到引用,我会更高兴。不幸的是,我对§8.9.5的解读是,即使是未处理的异常也会导致执行堆栈的所有finally语句执行。

答案 1 :(得分:3)

问题可能是您在调试器中运行代码。这意味着在未处理的异常之后的任何代码都不会被执行,因为调试器将在那时停止。

如果从调试器中运行测试场景,则在运行时清除混乱时将调用Dispose()方法。在Dispose()方法中放置一些代码“marker”,它将为您提供一个可见的符号来调用Dipose:例如,在一些名为 DisposedHasRun.yeah 的可访问文件夹中创建一个文件(注意输出到控制台或MessageBox不是一个选项,因为应用程序因未处理的异常而退出)。在调试器外部运行测试用例时,您将看到该文件已创建。

也就是说,有些Dispose不会被调用(也不是finally块)。例如,由于无限递归导致的StackOverflow异常不会调用Dispose(),因为运行时将使应用程序尽快解除。 (ThreadAbortException我认为行为相同)

答案 2 :(得分:-1)

在您的评论中,您说您在处置中使用此代码

System.IO.FileStream fs = new System.IO.FileStream(@"C:\exception.txt",
                                                   System.IO.FileMode.CreateNew);
fs.Write(Encoding.Unicode.GetBytes("object disposed"), 0, Encoding.Unicode.GetBytes("object disposed").Length); 
fs.Close();

如果您了解FileStream FileMode的工作方式;

  

CreateNew

     

指定操作系统应创建新文件。这个   需要FileIOPermissionAccess.Write权限。如果文件已经存在   存在,抛出IOException异常。

我很确定你的dispose抛出异常,因为该文件已经存在。

检查文件是否存在,然后根据需要使用System.IO.FileMode.Append