2010-10-14 1 views
14

El siguiente código genera dos advertencias de CA2000 (entre otros, pero ese no es el punto).¿Cómo deshacerse de la advertencia CA2000 cuando se transfiere la propiedad?

public sealed class Item: IDisposable 
{ 
    public void Dispose() {} 
} 

public sealed class ItemContainer 
{ 
    public void Add(Item item) 
    { 
    } 
} 

public sealed class Test: IDisposable 
{ 
    private ICollection<Item> itemCollection; 
    private ItemContainer itemContainer; 

    private void Add(Item item) 
    { 
     itemCollection.Add(item); 
    } 

    public void Initialize() 
    { 
     var item1 = new Item(); // no warning 
     itemCollection.Add(item1); 

     var item2 = new Item(); // CA2000: call Dispose on object item2 
     Add(item2); 

     var item3 = new Item(); // CA2000: call Dispose on object item3 
     itemContainer.Add(item3); 
    } 

    public void Dispose() {} 
} 

Tenga en cuenta que no se genera ninguna advertencia para el elemento1. Parece que Code Analysis asume que el ICollection se hará cargo del artículo y eventualmente lo eliminará.

¿Hay alguna manera de marcar mis métodos Add, para que la advertencia desaparezca?

Estoy buscando algo similar a ValidatedNotNullAttribute para CA1062.

Editar: para que quede claro: este no es mi código real. En el código real, todo está correctamente dispuesto.

Es solo que CA no reconoce que la llamada a mis métodos Add transfiere la propiedad. Me gustaría que tratara mis métodos Agregar de la misma manera que trata ICollection.Add.

Desechar en el mismo ámbito no es una opción.

Respuesta

6

También me preguntó esto en connect.microsoft.com y esto es lo que ellos respondieron:

Usted puede solucionar el problema haciendo que el objeto contenedor/colección que añade el objeto desechable implementar ICollection o ICollection <T> . El método que realiza el Add también debe tener un nombre que comience con "Agregar".

Y por supuesto: cuando la clase Prueba implementa ICollection < artículo >, entonces la advertencia desaparece. Esta es una solución aceptable para el caso en cuestión. Pero todavía es una pregunta abierta qué hacer, cuando no es apropiado implementar ICollection para indicar la transferencia de propiedad.

public sealed class Test: IDisposable, ICollection<Item> 
{ 
    public void Initialize() 
    { 
     var item1 = new Item(); // no warning 
     itemCollection.Add(item1); 

     var item2 = new Item(); // no warning 
     ((ICollection<Item>)this).Add(item2); 

     var item3 = new Item(); // no warning 
     AddSomething(item3); 
    } 

    //... implement ICollection and Method AddSomething 
} 
+0

He aceptado mi propia respuesta, porque esto es lo que hice en este caso: implementar ICollection en una clase que ya implementó IDisposable. Estoy totalmente de acuerdo con Damien: tendría más sentido, si CA requiere tanto IDisposable como ICollection. – Henrik

+0

¿Hay alguna manera de implementar algo similar en un diccionario de artículos desechables por índice? – Dave

9

¿Desea corregir el código o simplemente suprimir las advertencias? La supresión de las advertencias es sencillo:

[SuppressMessage("Microsoft.Reliability", 
       "CA2000:DisposeObjectsBeforeLosingScope", 
       Justification = "Your reasons go here")] 
public void Initialize() 
{ 
    // ... 
} 
+2

Preferiría ver eso con una justificación y así lo haría stylecop. – annakata

+1

@annakata: Y yo también. Editado para incluirlo ... – LukeH

+1

Preferiría no suprimir la advertencia. Si el método se modifica posteriormente, me gustaría recibir una advertencia, si corresponde. – Henrik

1

Bueno, por supuesto, lo primero que debe hacer es tener en realidad el método Dispose limpiar los miembros de la colección. Supongo que es solo un error en el ejemplo en lugar del código real.

Más allá de eso, simplemente suprimiría la advertencia. Sostengo firmemente que cualquier supresión:

  1. debe ser de un alcance muy corto, por lo que no suprime otro caso de la advertencia que es un error real.
  2. Debe anotarse con un comentario, sin importar cuán obvio sea el estado del cerebro, parece que la advertencia es segura de suprimir.

Dicho esto, creo que el análisis de CA2000 es tan pobre que no vale la pena comprobarlo por defecto, sino solo en revisiones ocasionales. Después de un cierto número de falsos positivos, una advertencia ya no puede considerarse una advertencia, solo ruido que oculta advertencias reales y, por lo tanto, hace que el código tenga más errores.

6

Sé que este es código de muestra, y por lo tanto, si esta solución funcionaría en su código real, no podría decirlo.

En este caso particular, si mueve el código de creación de objeto en su propio método, que devuelve el nuevo elemento, entonces la advertencia desaparecerá, p. cambio:

public void Initialize() 
{ 
    var item1 = new Item(); // no warning 
    itemCollection.Add(item1); 

    var item2 = CreateItem(); // CA2000 no longer appears 
    Add(item2); 

    var item3 = new Item(); // CA2000: call Dispose on object item3 
    itemContainer.Add(item3); 
} 

private Item CreateItem() 
{ 
    return new Item(); 
} 

Obviamente, el método CreateItem podría pasar parámetros arbitrarios para pasar al constructor del artículo.

Edición

Después de haber visto la respuesta de Henrik, y la respuesta de Connect, todo lo que puedo decir es bletch.No hay garantía de que una implementación de ICollection implemente IDisposable, y aunque su ejemplo publicado implementa IDisposable, aparentemente no es necesario para cerrar el análisis del código (Hubiera estado bastante bien si tuviera que implementar ambos). No es probable que una clase que implemente ICollection pero no implemente IDisposable se ocupe de la eliminación correcta de los objetos contenidos.

+0

Pero en este caso, la advertencia no aparecerá incluso si se elimina Add (elemento2) y el elemento2 no se elimina de forma verificable. Así que bien podría simplemente suprimir la advertencia. – Henrik

+0

@Henrik - cuanto más tiempo paso mirando esto, más me confundo. No hay garantía de que una implementación concreta de ICollection elimine correctamente los elementos añadidos, por lo que sigo preguntándome por qué * no * estamos obteniendo CA2000 para el elemento1. –

+0

Galardonado con la recompensa de esta respuesta. Esto podría ser útil en el caso en que el método CreateItem agregó el elemento internamente a una colección para asegurarse de que se eliminó. – Henrik

Cuestiones relacionadas