2014-09-09 2 views
3

Ниже приведен метод, который я использую для анализа XML. Он дает предупреждение CA2202 по анализу кода, в котором говорится, что объект mStream может быть удален несколько раз, и я не должен вызывать его более одного раза. Как я могу решить это предупреждение?Как исправить предупреждение CA2202?

public static String PrintXML(String XML) 
    { 
     String result = ""; 
     string[] xmlSeperators = new string[] { "<?" }; 
     string[] splitResults = new string[2]; 

     if (!String.IsNullOrEmpty(XML)) 
     { 
      using (MemoryStream mStream = new MemoryStream()) 
      { 
       using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode)) 
       { 
        XmlDocument document = new XmlDocument(); 
        try 
        { 
         // Load the XmlDocument with the XML. 
         //Check if it is only XML 
         if (XML.StartsWith("<?")) 
         { 
          document.LoadXml(XML); 
         } 
         else 
         { 
          //Split the string appended before XML 
          splitResults = XML.Split(xmlSeperators, 2, StringSplitOptions.None); 
          if (splitResults.Length > 1) 
          { 
           string d = "<?" + splitResults[1]; 
           document.LoadXml(d); 
          } 
         } 
         writer.Formatting = Formatting.Indented; 
         // Write the XML into a formatting XmlTextWriter 
         document.WriteContentTo(writer); 
         //xx.WriteTo(writer); 
         writer.Flush(); 
         mStream.Flush(); 
         // Have to rewind the MemoryStream in order to read its contents. 
         mStream.Position = 0; 
         // Read MemoryStream contents into a StreamReader. 
         StreamReader sReader = new StreamReader(mStream); 
         // Extract the text from the StreamReader. 
         String FormattedXML = sReader.ReadToEnd(); 

         if (splitResults[0] != null) 
         { 
          result = splitResults[0] + "\n" + FormattedXML; 
         } 
         else 
         { 
          result = FormattedXML; 
         } 
        } 
        catch (XmlException xe) 
        { 
         Log.Error(xe); 
         throw; 
        }       
       }     
      } 
     } 
     return result; 
    } 
+2

К сожалению XmlTextWriter не получить такие же перегрузки, как StreamWriter в .NET 4.5 (http://msdn.microsoft.com/en-us /library/gg712853(v=vs.110).aspx), так что вам нужно будет сделать то, что сказал Хабиб.Обычно я делаю такие вещи, как «новый XmlTextWriter (новый MemoryStream(), ...», чтобы было ясно, что XmlTextWriter владеет потоком, но на самом деле не подходит в вашем примере, потому что вы используете поток после создания XmlTextWriter. –

ответ

3

Причиной, побуждающей для получения этого предупреждения в том, что XmlTextWriter.Dispose() будет гарантировать, что под лежащим MemoryStream объект также расположен. Поэтому, когда заканчивается область usingMemoryStream, она попытается удалить объект MemoryStream и, следовательно, предупреждение.

using блок компилируется в блок try-finally. Внутренний using блок в вашем коде будет звонить Dispose на writer. Это назовет Dispose на вашем MemoryStream объекте mStream. При выходе из внутреннего блока управления внешний блок будет пытаться уничтожить объект writer, но поскольку он уже был удален, вы получаете предупреждение об инструменте анализа кода.

Чтобы избавиться от предупреждения, вы можете удалить первый оператор using и использовать блок try-finally. Но не забудьте установить mStream в null, как только вы введете второй оператор using. Это было объяснено в CA2202: Do not dispose objects multiple times

Ваш код будет выглядеть следующим образом:

public static String PrintXML(String XML) 
{ 
    String result = ""; 
    string[] xmlSeperators = new string[] { "<?" }; 
    string[] splitResults = new string[2]; 

    if (!String.IsNullOrEmpty(XML)) 
    { 
     MemoryStream mStream = null; 
     try 
     { 
      mStream = new MemoryStream(); 
      using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode)) 
      { 
       mStream = null; // important 
       XmlDocument document = new XmlDocument(); 
       try 
       { 
        // Load the XmlDocument with the XML. 
        //Check if it is only XML 
        if (XML.StartsWith("<?")) 
        { 
         document.LoadXml(XML); 
        } 
        else 
        { 
         //Split the string appended before XML 
         splitResults = XML.Split(xmlSeperators, 2, StringSplitOptions.None); 
         if (splitResults.Length > 1) 
         { 
          string d = "<?" + splitResults[1]; 
          document.LoadXml(d); 
         } 
        } 
        writer.Formatting = System.Xml.Formatting.Indented; 
        // Write the XML into a formatting XmlTextWriter 
        document.WriteContentTo(writer); 
        //xx.WriteTo(writer); 
        writer.Flush(); 
        mStream.Flush(); 
        // Have to rewind the MemoryStream in order to read its contents. 
        mStream.Position = 0; 
        // Read MemoryStream contents into a StreamReader. 
        StreamReader sReader = new StreamReader(mStream); 
        // Extract the text from the StreamReader. 
        String FormattedXML = sReader.ReadToEnd(); 

        if (splitResults[0] != null) 
        { 
         result = splitResults[0] + "\n" + FormattedXML; 
        } 
        else 
        { 
         result = FormattedXML; 
        } 
       } 
       catch (XmlException xe) 
       { 
        Log.Error(xe); 
        throw; 
       } 
      } 
     } 
     finally 
     { 

      if (mStream != null) 
      { 
       mStream.Dispose(); 
      } 

     } 
    } 
    return result; 
} 
+1

Спасибо за глубокое объяснение :) – Rex

0

Вы можете отключить предупреждение об ошибке, как другой ответ говорит, но actuall способ, чтобы удалить эту проблему на самом деле вызов метода .Dispose() только один раз в вашем коде, и только после того, как вы закончите работу с ним. Утилизированный объект будет вызывать исключение System.ObjectDisposedException, если вы его снова захотите, но не уверен. Правильный метод удаления может быть вызван на объект, несколько раз и будет/не может генерировать ошибку для вас. Но это не гарантировано.

Исправление для этого было заявлено Network Разработчик документа Microsoft,

Чтобы устранить нарушение данного правила, изменить реализацию таким образом, что независимо от пути кода, Dispose вызывается только один раз для объект.

Для более: http://msdn.microsoft.com/en-us/library/ms182334.aspx

0

Это происходит, когда у вас есть вложенные using заявления, где внутреннее заявление содержит ресурс от внешнего оператора. В этом случае XmlTextWriter будет утилизировать MemoryStream, когда он будет установлен, а затем внешний оператор using заставит его удаляться во второй раз.

Вы можете вручную распоряжаться MemoryStream путем замены внешнего using заявление с попыткой/наконец:

MemoryStream mStream = null; 
try 
{ 
    mStream = new MemoryStream(); 
    using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode)) 
    { 
     mStream = null; 
    ... 
    } 
} 
finally 
{ 
    if(mStream != null) 
     mStream.Dispose(); 
} 

(см http://msdn.microsoft.com/en-us/library/ms182334.aspx)

Смежные вопросы