StringWriter расположен не по всем путям исключений - PullRequest
4 голосов
/ 24 сентября 2010

Я работаю с 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 голосов
/ 24 сентября 2010

Ваш код допускает возможность того, что выброшенное исключение заставит выполнение пропустить оператор, закрывающий ваш 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();
    }
}

Обратите внимание, что вам не нужно вызывать оба Close и Dispose дляStringWriter.Достаточно просто Dispose.

В общем, вы захотите обернуть блок using вокруг создания и использования всех объектов, которые реализуют IDisposable (как это делает StringWriter).Это гарантирует, что независимо от того, какие исключения будут выброшены, объект всегда удаляется должным образом.

3 голосов
/ 24 сентября 2010

Второе предупреждение связано с тем, что 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();
}
...