A common using statement mistake in C#

Posted in software by Christopher R. Wirz on Tue Feb 18 2014

Using Statement Common Mistake with Writers in C#

For disposable (implements IDisposable) objects, the using statement helps clean up the code and illustrate the scope of the resource. However, attempting to clean up the code may have adverse effects.

Note: This article applies to writers. Readers do not have the same behavior. Also, you may not have the discussed problem with sufficiently small content passed to your writers.

Suppose we start with the following code, which is correct.


var str = "";
using (var stringWriter = new StringWriter())
{
	using (var xmlWriter = XmlWriter.Create(stringWriter))
	{
		((IXmlSerializable)serializable)?.WriteXml(xmlWriter);
	} 					// writes to the underlying StringWriter
	stringWriter.Flush(); 			// flushes/writes to the underlying StringBuilder (sometimes unnecessary)
	str = stringWriter.ToString();
}
return str;

Aside from putting it in a try-catch block, you may be inclined to change it to the following:


using (var stringWriter = new StringWriter())
using (var xmlWriter = XmlWriter.Create(stringWriter))
{
	((IXmlSerializable)serializable)?.WriteXml(xmlWriter);
	return stringWriter.ToString();
}

That's a lot cleaner, right? Yes, but it's WRONG! Don't change it. This is a writer.

Take a look at what happens when your serializable has a lot of data to write to the XmlWriter...
The first block of code will successfully prodcues the XML:

"<?xml version="1.0" encoding="utf-8"?..."

However, the second block of code returns this XML:

""

But wait, it didn't return anything?

Correct. While you might blame it on the null propegation, it is actually due to the scope of your resources. Basically, you are returning before the content has been written to the writer. What if you can garuntee the writer has been written to before returning? That helps. A block of code like this


using (var stringWriter = new StringWriter())
using (var xmlWriter = XmlWriter.Create(stringWriter))
{
	((IXmlSerializable)serializable)?.WriteXml(xmlWriter);
	xmlWriter.Flush();
	return stringWriter.ToString();
}

or

using (var stringWriter = new StringWriter())
{
	using (var xmlWriter = XmlWriter.Create(stringWriter))
	{
		((IXmlSerializable)serializable)?.WriteXml(xmlWriter);
	}
	return stringWriter.ToString();
}

would probably return
"<?xml version="1.0" encoding="utf-8"?..."
probably.

While this is well-and-good, a bit cleaner than returning outside the scope of the writer resources, it is just a band-aid. When a writing resource disposes, it flushes its contents - meaning it writes it out as desired. So, if you need the contents before the resource is disposed, call Flush() before getting said contents. Otherwise, work with the contents within the outer-most scope as possible. Please refer to the first block of code for the safest implementation.