C # CA2000: Desechar los objetos antes de perder el estudio que utilizan FileStream / XMLTextReader

StackOverflow https://stackoverflow.com/questions/3128446

Pregunta

Tengo un montón de código como el siguiente:

FileStream fs = File.Open(@"C:\Temp\SNB-RSS.xml", FileMode.Open); 
using (XmlTextReader reader = new XmlTextReader(fs)) 
{ 
   /* Some other code */
}

Esto me da la siguiente advertencia de análisis de código:

CA2000 : Microsoft.Reliability : In method 'SF_Tester.Run()', object 'fs' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'fs' before all references to it are out of scope.

Si sigo la sugerencia y pongo el File.Open en una instrucción using, me sale esto:

CA2202 : Microsoft.Usage : Object 'fs' can be disposed more than once in method 'SF_Tester.Run()'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.: Lines: 39

Estoy utilizando VS2010 y no puedo evitar pensar que estoy haciendo algo mal pero no verlo. ¿Qué estoy haciendo mal?

¿Fue útil?

Solución

Sigh, agotadora no lo es. Evitar todo esto mediante el uso de la cantidad recomendada de Crear () Método:

 using (var reader = XmlReader.Create(@"C:\Temp\SNB-RSS.xml")) {
     //...
 }

Otros consejos

Como nadie proporciona una solución que resuelve este problema, sin embargo, estoy escribiendo mi solución de trabajo de aquí abajo:

FileStream fs = new FileStream(fileName, FileMode.Truncate, FileAccess.ReadWrite,    FileShare.ReadWrite);
try
{
   using (var fileWriter = new StreamWriter(fs, encoding))
   {
       fs = null;
       fileWriter.Write(content);
    }
 }
 finally
 {
     if (fs != null)
         fs.Dispose();
 }

Esto elimina CA2000.

Sólo estoy adivinando; no tienen tiempo para ir a través de un análisis completo ahora.

Supongamos que el constructor XmlTextReader 'toma posesión' del flujo pasado, y así disponer el XmlTextReader también Dispose la corriente subyacente. Eso explicaría el comportamiento que se ve. Quizás constructor XmlTextReader puede lanzar, y en ese caso, la advertencia de original fs tendría sentido. Sin embargo, dado que la hipótesis, este código

        var fs = File.Open(@"C:\Temp\SNB-RSS.xml", FileMode.Open);
        XmlTextReader reader = null;
        try
        {
            reader = new XmlTextReader(fs);
        }
        finally
        {
            if (reader== null)
            {
                fs.Dispose();
            }
        }
        if (reader != null)
        {
            using (reader)
            {
                /* Some other code */
            }
        }

es, creo, correcta, pero todavía da una advertencia falsa. Esto huele como un ejemplo agradable que demuestra las limitaciones de las herramientas de análisis estático.

Como alguien dijo, hay otro API para crear directamente al lector del nombre de archivo (XmlReader.Create()), lo que evita todo esto (y demuestra lo bien diseñados-escenario-centrado API son una cosa buena para una sorprendente variedad de razones) .

Es un problema conocido

http: // connect .microsoft.com / VisualStudio / feedback / detalles / 535118 / CA2000-y-ca2202-oferta -contradictorio- advertencias

Si estás usando un StreamWriter en lugar de XMLTextReader (como en la solución anterior) se puede utilizar un método similar mediante el constructor correspondiente; por ejemplo.

var sw = new StreamWriter("filename.txt");

o

var sw = new StreamWriter("filename.txt", /*append to file = */ false );

No está claro a partir de la documentación si la primera forma de constructor se sobreponen o añadir a un archivo.

Como se mencionó en esta respuesta , la única forma de evitar de manera correcta es hacer como se recomienda en CA2202 y utilizar un try exterior -Por último bloque en lugar de un uso de bloque exterior. Dentro usando el interior, establecer el objeto IDisposable exterior a nulo para evitar que se accede una vez que el interior utilizando ha terminado.

Aquí hay un envoltorio genérico que hace "correctamente", es decir, trabaja en todo el XmlReader mal diseñado (propiedad tal vez no debería haber tomado de la corriente que recibe? No está seguro de cuál es la forma correcta de hacerlo sería)

Aviso Legal : En realidad no probado

public static TResult SafeNestedUsing<TOuter, TInner, TResult>(Func<TOuter> createOuterDisposable, Func<TOuter, TInner> createInnerDisposable, Func<TInner, TResult> body)
        where TInner : IDisposable
        where TOuter : class, IDisposable
    {
        TOuter outer = null;
        try
        {
            outer = createOuterDisposable();
            using (var inner = createInnerDisposable(outer))
            {
                var result = body(inner);
                outer = null;
                return result;
            }
        }
        finally
        {
            if (null != outer)
            {
                outer.Dispose();
            }
        }
    }

Ejemplo de uso:

SafeNestedUsing<MemoryStream, XmlReader, XmlDocument>(
    ()          => new MemoryStream(array),
    (memStream) => XmlReader.Create(memStream, xmlReaderSettings),
    (xmlReader) =>
    {
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(xmlReader);
        return xmlDoc;
    });

Este es bastante torpe, y es posible argumentar que es mejor repetir el try / conjunto nulo / patrón finalmente en su lugar. Pero para un patrón repetitivo de usings anidados prefiero hacerlo de esta manera que repetir la cosa completa cada vez.

solo uso 'utilizar' para el filestream

 using(FileStream fs = new FileStream(fileName, FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
// some codes here

}

No modifique fs y no utilice fs.close () en el interior se utilizan llaves.

Utilice la instrucción using también de la misma al igual que en el XMLTextReader FileStream.

http: // MSDN. microsoft.com/en-us/library/system.io.filestream(VS.71).aspx .

grz, Kris.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top