Вложенные операторы и анализаторы кода Microsoft
Недавно я включил дополнительные правила анализа кода.
К моему удивлению, я видел нарушение в месте, которое я всегда рассматривал как наилучшую практику.
Если у меня есть два вложенных одноразовых ящика, я помещаю два таких оператора:
using (StringReader strReader = new StringReader(xmlString))
using (XmlReader xmlReader = XmlReader.Create(strReader))
{
result.ReadXml(xmlReader);
}
Это также соответствует высокому Q & A
Вложенные операторы на С#
Нарушение Я получаю следующие состояния:
Warning 18 CA2202 : Microsoft.Usage : Object 'strReader' can be disposed more
than once in method '????'. To avoid generating a System.ObjectDisposedException
you should not call Dispose more than one time on an object.: Lines: ??
То, что я делал, было интуитивно понятным попыткой и ошибкой, считая, что закрытие внешнего потока также, вероятно, удалит внутренний, я быстро исправил свой код следующим образом:
using (XmlReader xmlReader = XmlReader.Create(new StringReader(xmlString)))
{
result.ReadXml(xmlReader);
}
Hura! Предупреждение исчезло. Но, тада! Новый произошел:
Warning 18 CA2000 : Microsoft.Reliability : In method '????????', object
'new StringReader(xmlString)' is not disposed along all exception paths. Call
System.IDisposable.Dispose on object 'new StringReader(xmlString)' before all
references to it are out of scope.
Тогда я нашел очень уродливое решение:
{
StringReader strReader = null;
try
{
strReader = new StringReader(xmlString);
using (XmlReader xmlReader = XmlReader.Create(strReader))
{
strReader = null;
result.ReadXml(xmlReader);
}
}
finally
{
if (strReader != null) strReader.Dispose();
}
}
Как последний шаг (как и любой хороший программист), я просмотрел справочную страницу для CA2202, и, к моему удивлению, именно мое последнее решение UGLY было предложено исправить проблему?
Попробуй {} наконец-то, используя беспорядок код очень! Для меня это вложенное использование, более читаемое.
Вопрос: Есть ли лучший способ сделать что-то? Я ищу решение, которое будет интуитивно понятным. Каждый, кто увидит этот последний фрагмент, будет любопытным о том, что происходит.
Заранее благодарим за ваши ответы.
Ответы
Ответ 1
Проблема не из-за вложенных запросов. Они в порядке и в целом рекомендуются. Проблема здесь в том, что XmlReader
будет располагать TextReader
, если вы передадите XmlReaderSettings
с помощью CloseInput == true
, но правило CA2202 недостаточно интеллектуально, чтобы ваш код не сходил с этой ветки. Держите свои вложенные слова и подавляйте нарушение CA2202 как ложный результат.
Если вы хотите быть явным в своем коде, чтобы повысить его читаемость и/или ремонтопригодность, используйте XmlReaderSettings
с CloseInput
, установленным в false
, но это значение по умолчанию, поэтому оно не является строго необходимым, и, быть ясно, не будет удовлетворять правилу.
Кстати, существуют похожие сценарии CA2202 для различных типов потоков и считывателей. К сожалению, они не все такие же, как и в этом случае, поэтому наилучшая обработка сообщений может различаться в зависимости от того, какой тип является причиной проблемы.
Ответ 2
Недавно у меня была аналогичная проблема, но поскольку я использовал сериализатор, мне пришлось адаптировать его, поскольку я не смог сразу установить stringWriter. Это обходное решение позволяет избежать всех предупреждений CA:
StringWriter stringWriter = null;
XmlWriter xmlWriter = null;
string serializedValue = null;
try
{
XmlSerializer xmlserializer = new XmlSerializer(typeof(T));
stringWriter = new StringWriter();
xmlWriter = XmlWriter.Create(stringWriter);
xmlserializer.Serialize(xmlWriter, value);
xmlWriter.Flush();
serializedValue = stringWriter.ToString();
}
finally
{
if (xmlWriter != null) //Both objects need disposed
{
xmlWriter.Dispose(); //stringWriter will dispose automatically too
}
else if (stringWriter != null) //XmlWriter failed to create
{
stringWriter.Dispose(); //just dispose stringWriter
}
}