CA2000/CA2202 для Stream в операторе использования

Предупреждения CA2000 и CA2202 недавно были проклятием моего существования. Что я здесь не так делаю? Я в основном получаю FileStream с помощью File.Open а затем передать его в функцию, которая может вернуть новый поток или может вернуть тот же поток. Затем я выполняю еще несколько действий в моем потоке, а затем в моем finally Блок Я распоряжаться потоком, который я использовал, если он был другим.

Я получил два предупреждения CA 2000 для fileStream в using блок и 2202 для changedStream в finally блок. Что дает?

using (Stream fileStream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    Stream changedStream = null;
    try
    {
        changedStream = someCondition ? fileStream : DoSomeActionThatMayReturnNewStream(fileStream);
        DoSomeMoreStuffWithStream(changedStream);
    }
    finally
    {
        if (changedStream != null && changedStream != fileStream)
        {
            changedStream.Dispose();
        }
    }
}

2 ответа

При каких случаях, если таковые имеются, будет DoSomeActionThatMayReturnNewStream избавиться от переданного потока? Если, когда он создает новый поток, он избавляется от переданного (что обычно ожидается), Dispose вызвано using блок будет избыточным.

Кажется, что поведение вашего кода может быть правильным, если DoSomeActionThatMayReturnNewStream никогда не избавляется от переданного потока, но FxCop не имеет возможности анализировать его сложную и неортодоксальную модель владения объектом. Я бы предположил, что было бы лучше сделать что-то вроде

Stream inputFile = null;
try
{
  inputFile = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
  DoSomeActionThatMayReturnNewStream(ref inputFile);
  DoSomeMoreStuffWithStream(inputFile);
}
finally
{
  if (inputFile != null)
    inputFile.Dispose();
}

DoSomeActionThatMayReturnNewStream должен избавиться от старого потока, если он собирается открыть новый. Она должна обнулять переменную непосредственно перед закрытием старого потока и назначать ее сразу после открытия нового. Это гарантирует, что если во время метода возникнет исключение, старый поток будет удален тогда и только тогда, когда он не был удален ранее, а новый поток будет удален, если его конструктор завершен, даже если DoSomeActionThatMayReturnNewStream бросил исключение после этого [если этот метод вызывает Dispose в новом потоке в случае возникновения исключения, в этом случае он должен обнулять переменную].

Что не так со следующим:

using (var fileStream = System.IO.File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    using (var changedStream = someCondition ? fileStream : DoSomeActionThatMayReturnNewStream(fileStream))
    {
        DoSomeMoreStuffWithStream(changedStream);
    }
}
Другие вопросы по тегам