如果我在using-block中使用对象初始值设定项,我会收到有关未正确处理对象的代码分析警告:
CA2000:Microsoft.Reliability:在方法'ReCaptcha.CreateReCaptcha(this HtmlHelper,string,string)'中,对象'<> g__initLocal0'未沿所有异常路径放置。在对所有引用超出范围之前,调用System.IDisposable.Dispose对象'<> g__initLocal0'。
以下是代码:
using (var control = new ReCaptchaControl()
{
ID = id,
Theme = theme,
SkipRecaptcha = false
})
{
// Do something here
}
如果我不使用对象初始值设定项,代码分析很高兴:
using (var control = new ReCaptchaControl())
{
control.ID = id;
control.Theme = theme;
control.SkipRecaptcha = false;
// Do something here
}
这两个代码块有什么区别?我认为他们会导致相同的IL。或者这是代码分析引擎中的错误吗?
答案 0 :(得分:32)
不,有区别。
对象初始值设定项仅在设置了所有属性后才分配给变量。换句话说,这个:
Foo x = new Foo { Bar = "Baz" };
相当于:
Foo tmp = new Foo();
tmp.Bar = "Baz";
Foo x = tmp;
这意味着如果其中一个属性设置器在您的情况下抛出异常,则不会丢弃该对象。
编辑:我想......试试这个:using System;
public class ThrowingDisposable : IDisposable
{
public string Name { get; set; }
public string Bang { set { throw new Exception(); } }
public ThrowingDisposable()
{
Console.WriteLine("Creating");
}
public void Dispose()
{
Console.WriteLine("Disposing {0}", Name);
}
}
class Test
{
static void Main()
{
PropertiesInUsingBlock();
WithObjectInitializer();
}
static void PropertiesInUsingBlock()
{
try
{
using (var x = new ThrowingDisposable())
{
x.Name = "In using block";
x.Bang = "Ouch";
}
}
catch (Exception)
{
Console.WriteLine("Caught exception");
}
}
static void WithObjectInitializer()
{
try
{
using (var x = new ThrowingDisposable
{
Name = "Object initializer",
Bang = "Ouch"
})
{
// Nothing
}
}
catch (Exception)
{
Console.WriteLine("Caught exception");
}
}
}
输出:
Creating
Disposing In using block
Caught exception
Creating
Caught exception
注意没有“Disposing Object initializer”行。