首页 文章

StringWriter未沿所有异常路径放置

提问于
浏览
4

我正在使用 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);
    }
}

为什么要生成这些警告?

2 回答

  • 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上同时调用 CloseDispose . 只需 Dispose 就足够了 .

    通常,您需要围绕创建和使用实现 IDisposable 的所有对象(如 StringWriter )来包装 using 块 . 这将确保无论抛出什么异常,对象总是被正确处理掉 .

  • 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();
    }
    

相关问题