Подтвердить что ты не робот

Вложенные операторы и анализаторы кода 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 было предложено исправить проблему?

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

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

Заранее благодарим за ваши ответы.

4b9b3361

Ответ 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
    }
}