C # Ca2000: Утилизация объектов перед потерей объем с использованием FileStream / XMLTExtreader

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

Вопрос

У меня много таких кодов:

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

Это дает мне следующий анализ кода Предупреждение:

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.

Если я следую по предложению, и я поставил файл.Open в используемом операторе, я получаю это:

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

Я использую VS2010, и я не могу не думать, что я делаю что-то не так, но я этого не вижу. Что я делаю неправильно?

Это было полезно?

Решение

Вздох, утомительно не так. Избегайте всего этого, используя рекомендуемый метод Create ():

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

Другие советы

Как никто не предоставил решение, который еще решает этот вопрос, я пишу свое рабочее решение здесь:

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

Это удаляет CA2000.

Я только догадываюсь; У вас нет времени пройти полный анализ сейчас.

Предположим XmlTextReader Конструктор «берет на себя ответственность» потока, переданного, и поэтому утилизации XmlTextReader будет также Dispose базовый поток. Это объяснило бы поведение, которое вы видите. Возможно XmlTextReader Конструктор может бросить, и в этом случае оригинал предупреждение о fs будет иметь смысл. Однако, учитывая эту гипотезу, этот код

        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 */
            }
        }

Я думаю, правильно, но все же уступает ложное предупреждение. Это запахи, как хороший пример, который демонстрирует ограничения инструментов статического анализа.

Как кто-то еще сказал, есть еще один API для непосредственного создания читателя из имени файла (XmlReader.Create()), что позволяет избежать всего этого (и показывает, насколько хорошо спроектированные сценарионные API - это хорошая вещь для удивительного разнообразия причин).

Это известная проблема

http://connect.microsoft.com/visualstudio/feedback/details/535118/ca2000-and-ca2202-offer-contictory-wardings

Если вы используете Streamwriter, а не XMLTEXTEXTER (как в решении выше), вы можете использовать аналогичный метод через соответствующий конструктор; например

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

или

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

Из документации не ясно, будет ли первая форма конструктора перезаписать или добавить к файлу.

Как уже упоминалось это ответ, единственный способ обойти его правильно Как рекомендуется в CA2202 и используйте внешнюю попытку, наконец-то блок вместо внешнего с использованием блока. Внутри внутреннего съемка установите внешний объект IDisposable для NULL, чтобы предотвратить его доступ, после завершения внутреннего использования внутреннее.

Вот общая обертка, которая делает это «правильно», то есть работает вокруг плохо разработанного XMLReader (может быть, не должно было предпринять владение потоком, которое он получает? Не уверен, какой правильный путь это будет)

Отказ от ответственности: Не совсем проверено

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

Пример использования:

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

Этот является Довольно неуклюже, и вы можете утверждать, что вместо этого лучше повторить попытку / установить нуль / наконец-то. Но для повторяющегося рисунка вложенных привлечений я бы предпочел сделать это таким образом, чем повторять полную вещь каждый раз.

Просто используйте «Использование» для FileStream

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

}

Не изменяйте FS и не используйте Fs.close () внутри, используя фигурные скобки.

Использовать using Заявление также на сам FileStream так же, как на XMLTExtreader.

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

ГРЗ, Крис.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top