Подтвердить что ты не робот

Это нормально, делая возврат изнутри с помощью блока

Я делаю обзор кода и нашел много кода в следующем формате:

public MyResponse MyMethod(string arg)
{
    using (Tracer myTracer = new Tracer(Constants.TraceLog))
    {
        MyResponse abc = new MyResponse();

        // Some code

        return abc;
    }
}

Когда я запускаю анализ кода, я получаю предупреждение CA2000 Microsoft.Reliability

Если код должен быть переписан как:

public MyResponse MyMethod(string arg)
{
   MyResponse abc = new MyResponse();

   using (Tracer myTracer = new Tracer(Constants.TraceLog))
   {
       // Some code
   }
   return abc;
}

Или это не имеет значения?

Edit

Линией, на которой сообщается о предупреждении, является:

MyResponse abc = new MyResponse();

MyResponse - это стандартный набор данных.

Полное сообщение об ошибке:

Предупреждение 150 CA2000: Microsoft.Relability: В методе 'xxxxx (Guid, Guid)' объект 'MyResponse' не расположен по всем путям исключений. Вызовите System.IDisposable. Задайте объект "MyResponse" перед тем, как все ссылки на него выходят за рамки.

4b9b3361

Ответ 1

Ваш rewrite не будет исправлять это предупреждение CA2000, потому что проблема не в объекте Tracer, а в объекте MyResponse.
В документации указано:

Ниже приведены некоторые ситуации, когда оператор using недостаточно для защиты объектов IDisposable и может привести к возникновению CA2000.
Возврат одноразового объекта требует, чтобы объект был сконструирован в блоке try/finally вне используемого блока.

Чтобы исправить предупреждение без использования трассировки стека ваших исключений (< - click, это ссылка), используйте это код:

public MyResponse MyMethod(string arg)
{
   MyResponse tmpResponse = null;
   MyResponse response = null;
   try
   {
       tmpResponse = new MyResponse();

       using (Tracer myTracer = new Tracer(Constants.TraceLog))
       {
           // Some code
       }

       response = tmpResponse;
       tmpResponse = null;
    }
    finally
    {
        if(tmpResponse != null)
            tmpResponse .Dispose();
    }
    return response;
}

Почему? См. Пример в связанной документации.

Ответ 2

Нет, это не имеет значения.

Блок finally, который неявно генерируется оператором using для обработки удаления, будет выполняться независимо от того, где вы помещаете return.

Вы уверены, что CA2000 относится к myTracer, а не abc? Я предполагаю, что предупреждение происходит потому, что MyResponse реализует IDisposable, и вы не удаляете abc перед возвратом. (В любом случае, ваш предлагаемый переписать не должен иметь никакого значения для предупреждения.)

Ответ 3

Предупреждение, вероятно, о MyResponse, которое IDisposable.

Почему появляется предупреждение?

Если объект MyResponse создан, но код позже в методе вызывает исключение, то все ссылки на этот объект будут потеряны (у нас был только один, и он не смог его вернуть). Это означает, что Dispose больше нельзя вызывать на объекте, и мы будем полагаться на финализатор класса для очистки любых ресурсов.

Это имеет значение?

Вообще говоря, это будет иметь значение только если:

  • IDisposable инкапсулирует ресурс, который может понадобиться "скоро" другими частями программы или другим процессом.
  • Перед возвратом метода генерируется исключение, чтобы вызвать "проблему"
  • Этот ресурс не будет выпущен финализатором в ближайшее время или по какой-либо причине финализатор никогда не запускается, но ваше приложение не опускается

Нет, это не имеет большого значения.

Как это исправить?

public MyResponse MyMethod(string arg)
{
    MyResponse abc = null;
    try {
        abc = new MyResponse();
        using (Tracer myTracer = new Tracer(Constants.TraceLog))
        {
            // Some code
           return abc;
        }
    }
    catch {
        if (abc != null) {
            abc.Dispose();
        }

        throw;
    }
}

Это гарантирует, что, если управление завершает метод с помощью исключения, abc либо null, либо был правильно установлен.

Update

Получается, что при использовании этого способа обработки исключение, явно выведенное изнутри MyMethod, будет возвращено и иметь номер строки первого стекового фрейма, который будет мутировать, чтобы указать на оператор throw;.

Практически это означает, что если у вас есть несколько операторов throw внутри MyResponse, и они генерируют один и тот же тип исключения с тем же сообщением, вы не сможете сказать, какой throw был ответственен именно тогда, когда вы ловите исключение.

Это ИМХО чисто академическая проблема, но я упоминаю ее для полноты.

Ответ 4

Это не имеет большого значения. Но, вопреки @Aliostad, я думаю, что версия 2 с return вне блока using является лучшим стилем.

Мое рассуждение выглядит следующим образом:

Блок using обозначает то, что "открыто" и "закрыто". Это своего рода сделка с чипом. Закрытие блока using говорит о том, что мы выполнили свою работу, и теперь безопасно продолжать другие вещи, например return ing.

Ответ 5

Это предупреждение, вероятно, связано с принципом "единственной точки выхода". Здесь обсуждается: http://c2.com/cgi/wiki?SingleFunctionExitPoint