2010-08-18 13 views
18

Si uso inicializadores de objeto en el uso de bloques consigo el análisis de código de advertencia acerca de no disponer el objeto correctamente:inicializadores de objeto en el uso de bloques de análisis de código genera la advertencia CA2000

CA2000: Microsoft.Reliability: En el método 'ReCaptcha. CreateReCaptcha (este HtmlHelper, cadena, cadena) ', objeto' <> g__initLocal0 'no se elimina a lo largo de todas las rutas de excepción. Call System.IDisposable.Dispose en el objeto '<> g__initLocal0' antes de que todas las referencias a él estén fuera del alcance.

Aquí está el código:

 

    using (var control = new ReCaptchaControl() 
    { 
     ID = id, 
     Theme = theme, 
     SkipRecaptcha = false 
    }) 
    { 
     // Do something here 
    } 
 

Si yo no uso inicializadores de objeto, el análisis de código es feliz:

 

    using (var control = new ReCaptchaControl()) 
    { 
     control.ID = id; 
     control.Theme = theme; 
     control.SkipRecaptcha = false; 

     // Do something here 
    } 
 

¿Cuál es la diferencia entre esos dos bloques de código? Pensé que resultaría en la misma IL. ¿O es esto un error en el motor de análisis de código?

Respuesta

31

No, no hay una diferencia.

Un inicializador de objetos solo asigna a la variable después de todas las propiedades se han establecido. En otras palabras, esto:

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

es equivalente a:

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

Eso significa que si uno de los emisores de propiedad inició una excepción en su caso, el objeto podría no ser eliminado.

EDIT: Como pensé ... intente esto:

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"); 
     } 
    } 
} 

Salida:

Creating 
Disposing In using block 
Caught exception 
Creating 
Caught exception 

Nota cómo no hay ninguna línea de "Eliminación inicializador de objeto".

+1

Eso tiene sentido ahora que lo escribes. OMI es una trampa que se pasa por alto fácilmente. Afortunadamente, Visual Studio es más sabio que yo. – Tero

+1

@Jon - Entonces, es correcto concluir que 'No use la sintaxis del inicializador de objetos con un tipo que también implemente IDisposable'. (Dado que la expansión no está bajo nuestro control para corregir el problema señalado por el motor de CA). – Gishu

+2

@Gishu: Si le preocupa en absoluto que los instaladores de propiedades arrojen excepciones, sí. –

Cuestiones relacionadas