I am working with a StringWriter which I am passing to a method to write values in a foreach loop. I believe this is causing the generation of two warnings:
CA2000 : Microsoft.Reliability : In method ‘ToCsvService.ToCsv()’, object ‘sw’ is not disposed along all exception paths. Call System.IDisposable.Dispose on object ‘sw’ before all references to it are out of scope.
and
CA2202 : Microsoft.Usage : Object ‘sw’ can be disposed more than once in method ‘ToCsvService.ToCsv()’. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.
public string ToCsv()
{
IEnumerable<string> props = GetProperties();
StringWriter sw = new StringWriter(); // first warning here
sw.WriteLine(GetHeadings(props));
WriteValues(props, sw);
sw.Close();
string returnCsv = sw.ToString();
sw.Dispose(); // second warning here
return returnCsv;
}
I’ve left out GetProperties() from the list of methods called as it didn’t seem pertinent.
private string GetHeadings(IEnumerable<string> props)
{
string headings = String.Join(",",
props.Select(prop =>
_headings.ContainsKey(prop) ? _headings[prop] : prop));
return headings;
}
private void WriteValues(IEnumerable<string> props, StringWriter sw)
{
foreach (object obj in _collection)
{
var x = obj.GetType().GetProperties()
.Where(pi => props.Contains(pi.Name))
.Select(pi =>
_format.ContainsKey(pi.Name)
? String.Format("{0:" + _format[pi.Name] + "}",
pi.GetGetMethod().Invoke(obj, null))
: pi.GetGetMethod().Invoke(obj, null).ToString());
string values = String.Join<string>(",", x);
sw.WriteLine(values);
}
}
Why are these warnings being generated?
Your code allows for the possibility that a thrown exception causes execution to skip over the statement that closes your
StringWriter. You want to ensure that, before an exception causes execution to leaveToCSV, you closesw.The easiest way to handle this is with a
usingblock. An object constructed within ausingclause is guaranteed to be disposed before the scope of the block is exited:Note that you don’t need to call both
CloseandDisposeon the StringWriter. JustDisposeis enough.In general, you’ll want to wrap a
usingblock around the creation and use of all objects that implementIDisposable(asStringWriterdoes). That’ll ensure that, no matter what exceptions get thrown, the object is always disposed of properly.