StringWriter not located on all exception paths

I am working with StringWriter , which I pass to the method of writing values ​​in a foreach . I believe this causes two warnings to be generated:

CA2000: Microsoft.Relability: in the ToCsvService.ToCsv () method, the "sw" object is not located on all exception paths. Call System.IDisposable.Dispose on the 'sw' object before all references to it go out of scope.

and

CA2202: Microsoft.Usage: Object 'sw' can be deleted more than once in the ToCsvService.ToCsv () method. To avoid throwing a System.ObjectDisposedException, you should not throw Dispose more than once 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 forgot GetProperties() from the list of methods invoked, as it did not seem appropriate.

 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 generated?

+4
source share
2 answers

Your code allows you to exclude that the exception thrown causes execution to skip the statement that closes your StringWriter . You want to make sure that before the exception forces execution to leave ToCSV , you close sw .

The easiest way to handle this is with the using block. The object built in the using clause is guaranteed to be deleted before the block's scope is closed:

 public string ToCsv() { IEnumerable<string> props = GetProperties(); using (StringWriter sw = new StringWriter()) { sw.WriteLine(GetHeadings(props)); WriteValues(props, sw); return sw.ToString(); } } 

Note that you do not need to call either Close or Dispose on a StringWriter. Just Dispose enough.

In general, you'll want to wrap a using block around creating and using all objects that implement IDisposable (as StringWriter does). This ensures that no matter what exceptions are thrown, the object is always disposed of properly.

+10
source

The second warning is that StringWriter.Close () calls StringWriter.Dispose (), http://msdn.microsoft.com/en-us/library/system.io.stringwriter.close.aspx , so you call Dispose twice .

The first warning is that if there is an exception after the new StringWriter (), you do not have catch statements to call Dispose on it. I would suggest rewriting my code

 using (StringWriter sw = new StringWriter()) { sw.WriteLine(GetHeadings(props)); WriteValues(props, sw); return sw.ToString(); } 
+3
source

All Articles