2014-02-19 3 views
0

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

Я получаю два предупреждения 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(); 
     } 
    } 
} 

ответ

1

При каких случаях, если таковые имеются, будет 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 в новом потоке в случае возникновения исключения, он должен обнулить переменную в таком случае].

+0

Это было бы идеально, если бы я имел контроль над API 'DoSomeActionThatMayReturnNewStream'. Он действительно работает и вызывает «Stream.Close» в любое время, когда ему нужно создать новый поток. Но поскольку он не является параметром ref, нет способа сообщить вызывающему, что он это сделал. – sohum

+0

Кроме того, FxCop автоматически предполагает, что всякий раз, когда мы передаем поток в качестве параметра функции, которую он будет располагать/не удалять или он действительно анализирует функцию, в которую мы ее передаем? – sohum

+0

@sohum: По моему пониманию, FxCop знает, что несколько методов берут на себя ответственность за переданный параметр, но не могут вообще выводить такие вещи. Если бы вы контролировали API, использование параметра 'ref' позволило бы FxCop быть агностиком в отношении права собственности на объект. В противном случае, самое лучшее, что можно сделать, вероятно, использовать одну и ту же переменную для исходного и нового, и указать, что если вызов удастся, код будет нести ответственность за удаление объекта в переменной независимо от того, является ли он исходным или новый. Один из них не сможет использовать 'использование', но ... – supercat

0

Что случилось со следующим:

using (var fileStream = System.IO.File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
{ 
    using (var changedStream = someCondition ? fileStream : DoSomeActionThatMayReturnNewStream(fileStream)) 
    { 
     DoSomeMoreStuffWithStream(changedStream); 
    } 
} 
+0

Не будет ли это dispose fileStream дважды, если changeStream == fileStream? Один раз в каждом используемом блоке? – sohum

+0

Вы правы. Я думаю, вам понадобится 'if (someCondition) {DoSomeMoreStuffWithStream (fileStream);} else {using (var changedStream = DoSomeActionThatMayReturnNewStream (fileStream)) {DoSomeMoreStuffWithStream (changedStream);}' –

Смежные вопросы