Это нормально, делая возврат изнутри с помощью блока
Я делаю обзор кода и нашел много кода в следующем формате:
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" перед тем, как все ссылки на него выходят за рамки.
Ответы
Ответ 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