2010-05-12 14 views
10

Estoy volviendo la variable que estoy creando en una instrucción using dentro de la instrucción using (suena gracioso):devolver la variable utilizada para el uso dentro de la usando C#

public DataTable foo() 
{ 
    using (DataTable properties = new DataTable()) 
    { 
     // do something 
     return properties; 
    } 
} 

¿Esta Desechar las propiedades de las variables ??

Después de hacer esto mañana sigue recibiendo este Aviso:

Advertencia 34 CA2000: Microsoft.Reliability: En el método 'test.test', llame System.IDisposable.Dispose para el objeto 'propiedades' antes de que todas las referencias a está fuera del alcance.

alguna idea?

Gracias

+3

pesar de todo, esto es sólo un mal diseño y debe ser reelaborado. –

Respuesta

10

Si desea devolverlo, no se puede envolver en una declaración using, porque una vez que sale de las llaves, se encuentra fuera de alcance y se dispone.

Usted tendrá que crear una instancia de esta manera:

public DataTable Foo() 
{ 
    DataTable properties = new DataTable(); 
    return properties; 
} 

y llame Dispose() en él más tarde.

+4

Parece que 'foo()' == 'GetUsefulDataTable()' y el bloque 'using' debería ser lo que llama a esta función. –

9

sí, va a deshacerse de él - y luego devolverlo. Esto es casi siempre algo malo de hacer.

De hecho, para DataTable, Dispose casi nunca hace nada (la excepción es si está remotamente en algún lugar, IIRC), pero sigue siendo una mala idea en general. Normalmente debería considerar los objetos desechados como inutilizables.

+0

Entonces, ¿cuál sería el patrón correcto para devolver un objeto IDisposable desde un método sin activar la advertencia CA2000? –

+0

@Jhonny: No sé, para ser honesto, no he usado análisis de código como este. Esperaría que hubiera alguna forma de suprimir la advertencia. –

+0

@ JhonnyD.Cano-Leftware- Si va a crear instancias y devolver IDsposable cosas que necesita para disponer explícitamente en su código. El análisis de su código "debería" recoger que usted disponga esto en otro lugar de forma manual. – IanNorton

3

El punto de un bloque usando es crear un ámbito artificial para un valor/objeto. Cuando se completa el bloque de uso, el objeto se limpia porque ya no es necesario. Si realmente desea devolver el objeto que está creando, entonces no es un caso en el que desea usarlo.

Esto funcionará bien.

public DataTable foo() 
{ 
    DataTable properties = new DataTable(); 
    // do something 
    return properties; 
} 
+0

Funcionaría bien si tuviera un punto y coma más. = P – Jason

+0

Se corrigió el error tipográfico. – unholysampler

1

el código utilizando la palabra clave using expande a:

{ 
    DataTable properties = new DataTable(); 
    try 
    { 
     //do something 
     return properties; 
    } 
    finally 
    { 
     if(properties != null) 
     { 
      ((IDisposable)properties).Dispose(); 
     } 
    } 
} 

Su variable está dispuesta por la naturaleza de cómo el uso de las obras. Si desea poder devolver propiedades, no las ajuste en un bloque de uso.

7

Supuestamente, este es el modelo para un método de fábrica que crea un objeto desechable.Sin embargo, he visto aún el análisis de código se quejan de esto, también:

 Wrapper tempWrapper = null; 
     Wrapper wrapper = null; 

     try 
     { 
      tempWrapper = new Wrapper(callback); 
      Initialize(tempWrapper); 

      wrapper = tempWrapper; 
      tempWrapper = null; 
     } 
     finally 
     { 
      if (tempWrapper != null) 
       tempWrapper.Dispose(); 
     } 

     return wrapper; 

Esto debería garantizar que si falla la inicialización, el objeto está dispuesto correctamente, pero si todo lo que tiene éxito, una instancia no vendida se devuelve desde el método .

MSDN Artículo: CA2000: Dispose objects before losing scope.

+0

¿No es esto básicamente equivalente a un bloque catch? ¿Por qué no escribirías 'Wrapper x = null; try {...} catch {if (x! = null) x.Dispose(); } ' La intención no es solo un 100% más obvia, sino que evita la variable temporal innecesaria y la limpieza manual. – Juliet

+0

No estoy en desacuerdo. Pero acabo de ver esto recientemente, no porque estuviera preocupado por eliminar el objeto en caso de falla, sino porque estaba tratando de encontrar el patrón de código que eliminaría la advertencia de CA2000 sin que tuviera que suprimirlo mediante el atributo. El proceso de análisis de código comprueba específicamente si el objeto está dispuesto en un bloque finally debido a la naturaleza de la regla que se aplica. Percibo que esta pregunta es realmente sobre CA2000, no sobre deshacerse de objetos. – Toby

+1

@Juliet: a la sentencia 'catch' le falta un nuevo lanzamiento, e incluso con un nuevo lanzamiento, la semántica no es lo mismo que no tener un catch. Entre otras cosas, si el bloque 'try' contiene llamadas a algún método' blah' que podría causar una excepción, catch-and-rethrow hará que el seguimiento de la pila muestre el número de línea del re-lanzamiento en lugar de la llamada a ' blah' (el seguimiento de pila dentro de 'blah' será correcto, pero el número de línea para la llamada no será). – supercat

0

Las otras respuestas son correctas: tan pronto como sale del bloque de uso, su objeto es eliminado. El bloque de uso es ideal para asegurarse de que un objeto se elimine de manera oportuna, por lo que si no desea confiar en los consumidores de su función para recordar desechar el objeto más adelante, puede intentar algo como esto:

public void UsingDataContext (Action<DataContext> action) 
{ 
    using (DataContext ctx = new DataContext()) 
    { 
     action(ctx) 
    } 
} 

esta manera se puede decir algo como:

var user = GetNewUserInfo(); 
UsingDataContext(c => c.UserSet.Add(user)); 
Cuestiones relacionadas