我的名为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语句应该为我做。
答案 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