Вложено с помощью выписок и анализов кода Microsoft - PullRequest
25 голосов
/ 11 ноября 2011

Недавно я включил дополнительные правила анализа кода. К моему удивлению, я увидел нарушение в месте, которое я всегда считал лучшей практикой. Если у меня есть два вложенных одноразовых элемента, я помещаю два оператора using, например:

    using (StringReader strReader = new StringReader(xmlString))
    using (XmlReader xmlReader = XmlReader.Create(strReader))
    {
        result.ReadXml(xmlReader);
    }

Это также соответствует высокому рейтингу вопросов и ответов Вложено с помощью операторов в C #

Нарушение, которое я получаю, гласит:

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, и, к моему удивлению, именно мое последнее Гадкое решение было предложено для решения проблемы?

Попробовав, наконец, {}, используя очень много кода! Для меня это вложение гораздо более читабельно.

Вопрос: Есть ли лучший способ делать вещи? Я ищу решение, которое будет интуитивно понятно. Каждый, кто увидит этот последний фрагмент, будет интересоваться происходящим.

Заранее спасибо за ваши ответы.

Ответы [ 2 ]

21 голосов
/ 11 ноября 2011

Проблема не из-за вложенного использования.Они в порядке и обычно рекомендуется.Проблема здесь в том, что XmlReader избавится от TextReader, если вы передадите XmlReaderSettings с CloseInput == true, но правило CA2202 недостаточно умен, чтобы ваш код не проходил по этой ветви.Сохраняйте вложенные значения и подавляйте нарушение CA2202 как ложное срабатывание.

Если вы хотите быть явным в своем коде для улучшения его читабельности и / или удобства обслуживания, используйте XmlReaderSettings с CloseInput, установленным на false, но это значение по умолчанию, поэтомуне является строго необходимым, и, чтобы быть ясным, не будет удовлетворять правилу.

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

0 голосов
/ 01 февраля 2017

У меня недавно была похожая проблема, но, поскольку я использовал сериализатор, мне пришлось его адаптировать, так как я не мог сразу установить для stringWriter значение null.Этот обходной путь избегает всех предупреждений 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
    }
}
...