C # Ca2000: Утилизация объектов перед потерей объем с использованием FileStream / XMLTExtreader
Вопрос
У меня много таких кодов:
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 - это хорошая вещь для удивительного разнообразия причин).
Это известная проблема
Если вы используете 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..
ГРЗ, Крис.