Reputation: 1144
Below is a method that I use to parse an XML. It is giving the CA2202 warning on code analysis which says that the object mStream can be disposed multiple times and I should not call dispose more than once. How can I solve 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;
}
Upvotes: 3
Views: 1642
Reputation: 223187
The reason for getting this warning is that XmlTextWriter.Dispose()
will ensure that the under lying MemoryStream
object is also disposed. So when the using
scope of the MemoryStream
ends, it will try disposing the MemoryStream
object and hence the warning.
using
block compiles into a try-finally
block. Inner using
block in your code would call Dispose
on your writer
. That will call Dispose
on your MemoryStream
object mStream
. At the exit of control from inner using block, the outer using block will try to dispose the object writer
, but since it has already been disposed, you are getting the warning on Code analysis tool.
To get rid of the warning, you can remove the first using
statement and use a try-finally
block. But remember to set mStream
to null
as soon as you enter the second using
statement. This has been explained at CA2202: Do not dispose objects multiple times
Your code would look like:
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;
}
Upvotes: 3
Reputation: 2112
This happens when you have nested using
statements where the inner statement contains the resource from the outer statement. In this case, the XmlTextWriter
will dispose of the MemoryStream
when it is disposed, and then the outer using
statement will cause it to be disposed for a second time.
You can manually dispose the MemoryStream by replacing the outer using
statement with a 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)
Upvotes: 0
Reputation: 15860
You can Suppress the error warning as the other answer is saying, but the actuall way to remove this problem to actually calling the .Dispose()
method only once in your code and only after you're done working with it. A disposed object would raise, System.ObjectDisposedException exception if you dispose it again, but is not for sure. A correct dispose method can be called on an object, multiple times and will/might not generate an error for you. But is not guaranteed to do so.
The fix for this has been stated by Microsoft's Developer Network document,
To fix a violation of this rule, change the implementation so that regardless of the code path, Dispose is called only one time for the object.
For more: http://msdn.microsoft.com/en-us/library/ms182334.aspx
Upvotes: 1