using-block中的对象初始值设定项生成代码分析警告CA2000

如果我在using-block中使用对象初始值设定项,我会收到有关未正确处理对象的代码分析警告:

CA2000:Microsoft.Reliability:在方法’ReCaptcha.CreateReCaptcha(this HtmlHelper,string,string)’中,对象’ g__initLocal0’未沿所有异常路径放置。 在对对象’ g__initLocal0’的所有引用都超出范围之前,调用System.IDisposable.Dispose。

这是代码:

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 }
using (var control = new ReCaptchaControl()) { control.ID = id; control.Theme = theme; control.SkipRecaptcha = false; // Do something here } 

这两个代码块有什么区别? 我认为他们会产生相同的IL。 或者这是代码分析引擎中的错误?

不,有区别。

对象初始值设定项仅在设置了所有属性分配给变量。 换句话说,这个:

 Foo x = new Foo { Bar = "Baz" }; 

相当于:

 Foo tmp = new Foo(); tmp.Bar = "Baz"; Foo x = tmp; 

这意味着如果其中一个属性设置器在您的情况下引发exception,则不会丢弃该对象。

编辑:我想…试试这个:

 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”行。