这是我的电话采访问题:是否有时间不会在使用块声明范围的对象上调用Dispose?
我的回答是否定的 - 即使在使用块期间发生异常,仍会调用Dispose.
面试官不同意并说如果using包裹在try- catch块中,那么当你进入catch块时就不会调用Dispose.
这与我对构造的理解相反,我无法找到任何支持采访者观点的东西.他是正确的还是我误解了这个问题?
Øyv*_*hen 58
将导致Dispose无法在using块中调用的四件事:
StackOverflowException,AccessViolationException和其它可能的.Vde*_*edT 53
void Main()
{
try
{
using(var d = new MyDisposable())
{
throw new Exception("Hello");
}
}
catch
{
"Exception caught.".Dump();
}
}
class MyDisposable : IDisposable
{
public void Dispose()
{
"Disposed".Dump();
}
}
Run Code Online (Sandbox Code Playgroud)
这产生了:
Disposed
Exception caught
Run Code Online (Sandbox Code Playgroud)
所以我同意你的意见,而不是聪明的面试官......
Ian*_*Ian 25
奇怪的是,我读到了今天早上Dispose不会在使用区块中被调用的情况.在MSDN上查看此博客.当你不迭代整个集合时,它使用Dispose with IEnumerable和yield关键字.
不幸的是,这并不涉及异常情况,说实话,我不确定那个.我原本预计它会完成,但也许值得用快速的代码检查一下?
svi*_*ick 21
有关电源故障,其他的答案Environment.FailFast(),迭代器或作弊用using的东西,是null都很有趣.但我发现很奇怪没有人提到我认为最常见的情况,Dispose()即使存在以下内容也不会被调用using:当内部表达式using抛出异常时.
当然,这是合乎逻辑的:表达式using抛出一个异常,所以分配没有发生,我们也没有什么可以调用Dispose().但是一次性物体已经存在,尽管它可以处于半初始状态.即使在这种状态下它也可以拥有一些非托管资源.这是正确实施一次性图案的另一个重要原因.
有问题的代码示例:
using (var f = new Foo())
{
// something
}
…
class Foo : IDisposable
{
UnmanagedResource m_resource;
public Foo()
{
// obtain m_resource
throw new Exception();
}
public void Dispose()
{
// release m_resource
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,它看起来像正确Foo发布m_resource,我们也using正确使用.但由于例外,从未调用Dispose()on Foo.在这种情况下的修复是使用终结器并在那里释放资源.
cHa*_*Hao 19
该using块被编译器变成了try/ finally它自己的块,内现有的try块.
例如:
try
{
using (MemoryStream ms = new MemoryStream())
throw new Exception();
}
catch (Exception)
{
throw;
}
Run Code Online (Sandbox Code Playgroud)
变
.try
{
IL_0000: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
IL_0005: stloc.0
.try
{
IL_0006: newobj instance void [mscorlib]System.Exception::.ctor()
IL_000b: throw
} // end .try
finally
{
IL_000c: ldloc.0
IL_000d: brfalse.s IL_0015
IL_000f: ldloc.0
IL_0010: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0015: endfinally
} // end handler
} // end .try
catch [mscorlib]System.Exception
{
IL_0016: pop
IL_0017: rethrow
} // end handler
Run Code Online (Sandbox Code Playgroud)
编译器不会重新排列内容.所以它发生如下:
using块的try部分using块的try一部分,并进入其finally部分finally块中的代码处理trytry并进入异常处理程序指出,内部finally块总是在外部之前运行catch,因为异常不会传播直到finally块完成.
这种情况不会发生的唯一正常情况是发生器(对不起,"迭代器").迭代器变成一个半复杂的状态机,finally如果在一个yield return(但在它被处理之前)它变得无法访问,则不能保证块运行.
adr*_*anm 13
using (var d = new SomeDisposable()) {
Environment.FailFast("no dispose");
}
Run Code Online (Sandbox Code Playgroud)
是的,有一种情况下不会调用处理......你在想它.情况是使用块中的变量null
class foo
{
public static IDisposable factory()
{
return null;
}
}
using (var disp = foo.factory())
{
//do some stuff
}
Run Code Online (Sandbox Code Playgroud)
不会抛出异常,但会在每种情况下调用dispose.虽然你的面试官提到的具体案例是错误的.