Я счастлив, закодировал довольно проект, который отлично работает и не проявляет каких-либо странностей во время выполнения. Поэтому я решил запустить статический инструмент анализа кода (я использую Visual Studio 2010). Выяснилось, что правило CA2000
нарушается, сообщение выглядит следующим образом:
Предупреждение - CA2000: Microsoft.Reliability: В методе "Bar.getDefaultFoo()" вызовите System.IDisposable. Разместите объект "new Foo()" перед тем, как все ссылки на него выходят за рамки.
Указанный код выглядит следующим образом:
private static IFoo getDefaultFoo()
{
return (Baz.canIDoIt()) ? new Foo() : null;
}
Я подумал: возможно, условное выражение портит логику (мой или валидатор). Изменено:
private static IFoo getDefaultFoo()
{
IFoo ret = null;
if (Baz.canIDoIt())
{
retFoo = new Foo();
}
return ret;
}
То же самое произошло снова, но теперь объект назывался retFoo
. Я googled, я msdn'ed, у меня есть stackoverflow'ed. Найдено в этой статье. После создания объекта никаких операций не требуется. Мне нужно вернуть ссылку на него. Однако я попытался применить шаблон, предложенный в примере OpenPort2. Теперь код выглядит следующим образом:
private static IFoo getDefaultFoo()
{
Foo tempFoo = null;
Foo retFoo = null;
try
{
if (Baz.canIDoIt())
{
tempFoo = new Foo();
}
retFoo= tempFoo;
tempFoo = null;
}
finally
{
if (tempFoo != null)
{
tempFoo.Dispose();
}
}
return retFoo;
}
Такое же сообщение снова, но переменная tempFoo
является нарушителем правил на этот раз. Так что, в основном, код стал скрученным, дольше, немного иррациональным, неуклюже сложным и делает то же самое, но медленнее.
Я также нашел этот вопрос, где такое же правило, похоже, атакует действительный код аналогичным образом. И есть вопрос, чтобы игнорировать предупреждение. Я также прочитал эту тему и массу подобных вопросов.
Я что-то пропустил? Является ли правило прослушиванием/неуместным? Что мне делать? Игнорировать? Рукоятка каким-то магическим способом? Может быть, применить шаблон дизайна?
Edit:
После запроса Nicole я представляю весь связанный код в форме, которую я также пытался использовать.
public class DisposableFooTest
{
public interface IFoo
{
void bar();
}
public class Foo : IFoo, IDisposable
{
public void bar()
{
Console.Out.WriteLine("Foo baring now");
}
public void Dispose()
{
// actual Dispose implementation is irrelevant, or maybe it is?
// anyway I followed microsoft dispose pattern
// with Dispose(bool disposing)
}
}
public static class Baz
{
private static bool toggle = false;
public static bool canIDoIt()
{
toggle ^= true;
return toggle;
}
}
private static IFoo getDefaultFoo()
{
IFoo result = null;
try
{
if (Baz.canIDoIt())
{
result = new Foo();
}
return result;
}
catch
{
if (result != null)
{
(result as IDisposable).Dispose();
// IFoo does not inherit from IDisposable, hence the cast
}
throw;
}
}
public static void Main()
{
IFoo bar = getDefaultFoo();
}
}
Отчет об анализе содержит следующее:
`CA2000: Microsoft.Reliability: в методе 'DisposableFooTest.getDefaultFoo()' вызывать System.IDisposable.Dispose на объекте 'result', прежде чем все ссылки на него выходят за рамки. %% projectpath %%\DisposableFooTest.cs 44 Тест
Edit2:
Следующий подход разрешил проблему CA2000:
private static IFoo getDefaultFoo()
{
Foo result = null;
try
{
if (Baz.canIDoIt())
{
result = new Foo();
}
return result;
}
finally
{
if (result != null)
{
result.Dispose();
}
}
}
К сожалению, я не могу пойти так. Более того, я бы предпочел бы ожидать, что после объектно-ориентированных принципов, передовой практики и рекомендаций упростится код, сделайте его читабельным, универсальным и расширяемым. Я сомневаюсь, что кто-то прочитал его по назначению: дайте Foo, если возможно, или null в противном случае.