我想知道使用object initializers inside using statements是否会以某种方式阻止正确声明其中声明的资源,例如
using (Disposable resource = new Disposable() { Property = property })
{
// ...
}
我读到对象初始化程序不过是合意的糖,编译器将其翻译成类似于以下代码的东西:
MyClass tmp = new MyClass();
tmp.Property1 = 1;
tmp.Property2 = 2;
actualObjectYouWantToInitialize = tmp;
即使我可能表现为困惑的愚昧无知,我也想请您澄清一下。 (据我所知)初始化的对象是(据我所知)另一个对象的指针(据我所知也是指针)的事实是否干扰了using
语句对资源的处理?
答案 0 :(得分:6)
主要的(唯一的)危险是,如果设置Property
失败(即引发异常),则resource
won't be Dispose
d。
using (Disposable resource = new Disposable() { Property = property })
{
// ...
}
在using
块内 通常异常很好-因为using
是try .. finally
的语法糖。
这里的问题是,Property = property
正在有效执行您时还没有进入using
块内部。 与构造器引发异常时发生的事情本质上没有什么不同。
finally
块将尝试尝试Dispose
的事物是resource
-但从未设置resource
-resource
(如您的{ {1}}示例)设置为after the properties have all been set。
https://dotnetfiddle.net/vHeu2F显示了在实践中可能如何发生。请注意,即使有两个actualObjectYouWantToInitialize
块,Dispose
也被记录一次。
using
CA2000可能有助于发现此问题。
答案 1 :(得分:2)
@mjwills答案正确。详细信息如下:
public void M()
{
using (var x = new Test{Property = ""})
{
}
}
将生成以下IL代码:
.method public hidebysig
instance void M () cil managed
{
// Method begins at RVA 0x206c
// Code size 35 (0x23)
.maxstack 3
.locals init (
[0] class Test
)
IL_0000: nop
IL_0001: newobj instance void Test::.ctor()
IL_0006: dup
IL_0007: ldstr ""
IL_000c: callvirt instance void Test::set_Property(string)
IL_0011: nop
IL_0012: stloc.0
.try
{
IL_0013: nop
IL_0014: nop
IL_0015: leave.s IL_0022
} // end .try
finally
{
// sequence point: hidden
IL_0017: ldloc.0
IL_0018: brfalse.s IL_0021
IL_001a: ldloc.0
IL_001b: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0020: nop
// sequence point: hidden
IL_0021: endfinally
} // end handler
IL_0022: ret
} // end of method Test::M
您可以看到在进入try之前调用了属性设置器,这将导致在设置器发生异常的情况下最终不被调用。