How to fix warning CA2202?
Below is the method I am using to parse XML. It gives CA2202 code analysis warning, which says the mStream object can be deleted multiple times and I shouldn't call it more than once. How can I resolve this warning?
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;
}
source to share
The reason for receiving this warning is to XmlTextWriter.Dispose()
ensure that the underlying object is MemoryStream
also deleted. So when the area using
MemoryStream
ends, it will try to delete the object MemoryStream
and hence the warning.
using
compiles into a block try-finally
. An inner block using
in your code will call Dispose
on yours writer
. This will call Dispose
to your MemoryStream
object mStream
. When exiting the internal control unit, the external unit will try to destroy the object writer
, but since it has already been deleted, you get a warning about the code analysis tool.
To get rid of the warning, you can remove the first statement using
and use a block try-finally
. But don't forget to set mStream
tonull
as soon as you enter the second operator using
. This was explained in CA2202: Do not delete objects multiple times
Your code will look like this:
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;
}
source to share
You can suppress the error warning, as the other answer says, but that fixes the problem by actually calling the method .Dispose()
only once in your code and only after you're done working with it. The disposed object will throw a System.ObjectDisposedException if you want it again, but not sure. The correct delete method can be called on the object multiple times and will / cannot generate an error for you. But this is not guaranteed.
A fix for this was stated in the Microsoft Developer Network document.
To correct a violation of this rule, change your implementation so that, regardless of the code path, Dispose is called only once on an object.
More details: http://msdn.microsoft.com/en-us/library/ms182334.aspx
source to share
This happens when you have nested statements using
where the inner statement contains a resource from the outer statement. In this case, XmlTextWriter
will dispose MemoryStream
when it is deleted and then the external operator using
will force it to be deleted a second time.
You can manually remove the MemoryStream by replacing the outer statement using
with try / finally:
MemoryStream mStream = null;
try
{
mStream = new MemoryStream();
using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode))
{
mStream = null;
...
}
}
finally
{
if(mStream != null)
mStream.Dispose();
}
(see http://msdn.microsoft.com/en-us/library/ms182334.aspx )
source to share