我正在使用StringWriter
我将传递给在foreach
循环中写入值的方法。我相信这会导致产生两个警告:
CA2000:Microsoft.Reliability:在方法'ToCsvService.ToCsv()'中,对象'sw'未沿所有异常路径放置。在对所有引用超出范围之前,调用System.IDisposable.Dispose对象'sw'。
和
CA2202:Microsoft.Usage:对象'sw'可以在方法'ToCsvService.ToCsv()'中多次处理。为避免生成System.ObjectDisposedException,不应在对象上多次调用Dispose。
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;
}
我从调用的方法列表中遗漏了GetProperties()
,因为它似乎并不相关。
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);
}
}
为什么要生成这些警告?
答案 0 :(得分:10)
您的代码允许抛出的异常导致执行跳过关闭StringWriter
的语句。您希望确保在异常导致执行离开ToCSV
之前,您关闭sw
。
处理此问题的最简单方法是使用using
块。在using
子句中构造的对象保证在退出块的范围之前被处置:
public string ToCsv()
{
IEnumerable<string> props = GetProperties();
using (StringWriter sw = new StringWriter())
{
sw.WriteLine(GetHeadings(props));
WriteValues(props, sw);
return sw.ToString();
}
}
请注意,您无需在StringWriter上同时调用Close
和Dispose
。只需Dispose
即可。
通常,您需要围绕创建和使用实现using
的所有对象(如IDisposable
所做的那样)包装StringWriter
块。这将确保无论抛出什么异常,对象总是被妥善处理。
答案 1 :(得分:3)
第二个警告是因为StringWriter.Close()调用StringWriter.Dispose(),http://msdn.microsoft.com/en-us/library/system.io.stringwriter.close.aspx,所以你要调用两次Dispose。
第一个警告是因为如果在新StringWriter()之后出现异常,则没有任何catch语句来调用Dispose。我建议将代码重写为
using (StringWriter sw = new StringWriter()) {
sw.WriteLine(GetHeadings(props));
WriteValues(props, sw);
return sw.ToString();
}