Advertencia de Microsoft.usage cuando hay dos cláusulas using anidadas

Me pregunto por qué el análisis de código de Visual Studio da una advertencia con este pequeño código:

byte[] data = File.ReadAllBytes("myImage.png");
using (MemoryStream mem = new MemoryStream(data))
using (Bitmap bmp = new Bitmap(mem))            
{
     // do something with the bitmap
}

El error es:

El objeto 'mem' se puede desechar más de una vez en el método... Para evitar generar una System.ObjectDisposedException, no debe llamar a Dispose más de una vez en un objeto.

¿Y cómo corregir esto? (Sí, podría cargar el mapa de bits directamente desde el archivo, pero en mi proyecto real tengo mi propio formato de archivo donde se guardan varias imágenes en un solo archivo y, por lo tanto, necesito un MemoryStream para cargar los datos de un rango específico en el archivo)

preguntado el 29 de junio de 12 a las 20:06

No es una respuesta a su pregunta, pero "si se llama al método Dispose de un objeto más de una vez, el objeto debe ignorar todas las llamadas después de la primera. El objeto no debe generar una excepción si su método Dispose se llama varias veces". (Fuente) -

4 Respuestas

El problema es que Bitmap toma posesión de la secuencia que se le da en su constructor. It se deshará de la transmisión, no es necesario que lo haga. Así que todo lo que necesitas es:

using (Bitmap bmp = new Bitmap(new MemoryStream(data)))            
{
     // do something with the bitmap
}

Respondido el 29 de junio de 12 a las 20:06

Su código genera otra advertencia: Microsoft. Confiabilidad: en el método --- el objeto 'nuevo MemoryStream (datos)' no se elimina a lo largo de todas las rutas de excepción. Llame a System.IDisposable.Dispose en el objeto 'new MemoryStream(data)' antes de que todas las referencias a él estén fuera del alcance. - jaska

@Jon - Y MemoryStream.Dispose() es un tonto de todos modos. Pero todavía prefiero tener el using (MemoryStream mem = ...) en el código, simplemente porque es IDisposable. Es una advertencia contraproducente. - henk holterman

@Jaska: En ese caso, elegiría la forma de código que prefiera e ignoraría o suprimiría la advertencia. Para ser honesto, a menos que esté utilizando la comunicación remota con un MemoryStream, no importa si lo desecha o no de todos modos. - jon skeet

Ok, simplemente ignoraré eso. Esto me ha molestado durante mucho tiempo porque no pude encontrar nada malo en el código :) - jaska

con respecto a la segunda advertencia de confiabilidad, parece que cuando ocurre esta situación, el análisis de código se quejará con CA2000 or CA2202 independientemente de lo que hagas. Hay múltiples quejas sobre esto, aquí hay uno para su disfrute.

Solo para ver si es particular para usar la sintaxis, expandí el uso en un bloque de captura de prueba y obtienes el mismo comportamiento.

class Program
    {
        static void Main(string[] args)
        {
            byte[] data = {};
            //using (Bitmap bitmap = new Bitmap(new MemoryStream(data)))
            //{ }

            MemoryStream mem = null;
            Bitmap bitmap = null;
            try
            {
                mem = new MemoryStream(data);
                bitmap = new Bitmap(mem);

            }
            catch (Exception)
            {

                throw;
            }
            finally
            {
                if (null!= bitmap ) bitmap.Dispose();                
                // commenting this out will provoke a CA2000.
                // uncommenting this will provoke CA2202.
                // so pick your poison.
                // if (null != mem) mem.Dispose();
            }
        } 
    }

editar: hay, como usted (Jaska) señaló, una nota de Microsoft sobre la intención de marcar sobre el flujo de memoria en el bloque de uso del mapa de bits:

class Program
    {
        static void Main(string[] args)
        {
            byte[] data = new byte[1000];
            MemoryStream mem = null;
            try
            {
                mem = new MemoryStream(data);
                using (Bitmap bmp = new Bitmap(mem))
                {
                    mem = null; // <-- this line will make both warning go away
                }
            }
            finally
            {
                if (mem != null)
                {
                    mem.Dispose();
                }
            } 
        } 
    }

Me alegra ver que esto funciona, pero al mismo tiempo es un poco más feo que usar un flujo de memoria anónimo en el constructor del mapa de bits. Ah bueno.

Respondido el 29 de junio de 12 a las 22:06

sí, probé casi exactamente el mismo código y obtuve los mismos hallazgos. Este debe ser ignorado o suprimido :( - jaska

¡Tu respuesta me llevó a la solución para deshacerme de ambos! La solución es establecer el flujo de memoria en nulo dentro de la declaración de uso. Para su información, también @ John-Skeet, publicaré una respuesta en un minuto: jaska

Debido a que su enlace proporcionado me llevó a la solución, si desea que acepte su respuesta, refínela como en mi propia respuesta y aceptaré la suya. - jaska

El enlace de Reacher-Gilt a ms-page me llevó a la solución, que hará que desaparezcan ambas advertencias:

        byte[] data = new byte[1000];
        MemoryStream mem = null;
        try
        {
            mem = new MemoryStream(data);
            using (Bitmap bmp = new Bitmap(mem))
            {
                mem = null; // <-- this line will make both warning go away
            }
        }
        finally
        {
            if (mem != null)
            {
                mem.Dispose();
            }
        } 

Respondido el 29 de junio de 12 a las 21:06

Una vez que ingrese la segunda declaración de uso, su mapa de bits "consumirá" el flujo de memoria; se vuelve responsable por el flujo de memoria, incluida su eliminación. Esto es sensato, si piensa en su uso: ¿esperaría que algo más estuviera accediendo mem después (o durante) de haberlo usado en el constructor de su mapa de bits? Yo diría que probablemente no.

La respuesta es consolidar los dos usando declaraciones juntas: using (Bitmap bitmap = new Bitmap(new MemoryStream(data))). Eso debería encargarse de la advertencia de CA.

Respondido el 29 de junio de 12 a las 20:06

Genera otra advertencia: Microsoft. Confiabilidad: en el método --- el objeto 'nuevo MemoryStream (datos)' no se elimina en todas las rutas de excepción. Llame a System.IDisposable.Dispose en el objeto 'new MemoryStream(data)' antes de que todas las referencias a él estén fuera del alcance. - jaska

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.