Я просто хочу знать, безопасен ли / хороший подход для вызова return
внутри using
блока.
Например,
using(var scope = new TransactionScope())
{
// my core logic
return true; // if condition met else
return false;
scope.Complete();
}
Мы знаем, что последняя самая фигурная скобка dispose()
будет снята. Но что будет в приведенном выше случае, поскольку return
элемент управления переходит из заданной области (AFAIK) ...
- Мне
scope.Complete()
позвонят? - То же самое и с
dispose()
методом прицела .
using{}
область видимости закончится, соответствующие объекты будут удалены,return
"сломают" область видимости - так что объекты будут размещены должным образомscope.Complete()
вызов никогда не попадет предоставленный вами образец, поэтому ваша транзакция всегда будет откатываться.using
,dispose()
вызывается ли, когда вы вернетесь, функция, содержащая этотusing
блок, будет возвращена, и все, что ей принадлежит, станет бесхозным. Таким образом, даже еслиscope
он не был удален «самимusing
» (он будет, как объяснили другие), он все равно будет удален, потому что функция завершилась. Если бы в C # былgoto
оператор - вы еще не смеялись? хорошо - тогда вместо возврата вы можетеgoto
перейти после закрывающей скобки, не возвращаясь. Логично,scope
что все равно будет удалено, но вы только что добавилиgoto
C #, так что кого волнует логика на этом этапе.Ответы:
Совершенно безопасно вызывать
return
внутри вашегоusing
блока, поскольку используемый блок - это простоtry/finally
блок.В приведенном выше примере после возврата
true
область видимости будет удалена и значение будет возвращено.return false
Иscope.Complete()
будет не дозвонились.Dispose
однако будет вызываться независимо от того, что находится внутри блока finally.Ваш код по сути такой же (если это упрощает понимание):
var scope = new TransactionScope()) try { // my core logic return true; // if condition met else return false; scope.Complete(); } finally { if( scope != null) ((IDisposable)scope).Dispose(); }
Имейте в виду, что ваша транзакция никогда не будет зафиксирована, поскольку нет возможности
scope.Complete()
выполнить транзакцию.источник
Dispose
вас перезвонят. Если OP не знает, что происходитusing
, скорее всего, он не знает, что происходит сfinally
.using
, напримерusing (var callersVar = MyFunc(..)) ..
, вместо использования внутри "MyFunc" - я имею в виду, что вызывающему абоненту предоставляется поток и он отвечает за его закрытие черезusing
или явно, либо (б) пусть MyFunc извлечет всю необходимую информацию в другие объекты, которые можно безопасно передать обратно - тогда базовые объекты данных или поток могут быть удалены вашимusing
. Вам не нужно писать негерметичный код.Это нормально -
finally
предложения (что и делает закрывающая фигурная скобкаusing
предложения под капотом) всегда выполняются при выходе из области видимости, независимо от того, как.Однако это верно только для операторов, которые находятся в блоке finally (который не может быть явно установлен при использовании
using
). Следовательно, в вашем примереscope.Complete()
он никогда не будет вызван (хотя я ожидаю, что компилятор предупредит вас о недоступности кода).источник
В общем, подход хороший. Но в вашем случае, если вы вернетесь до вызова
scope.Complete()
, он просто уничтожит TransactionScope. Зависит от вашего дизайна.Итак, в этом примере Complete () не вызывается, а область видимости удаляется, предполагая, что она наследует интерфейс IDisposable.
источник
scope.Complete обязательно должен вызываться раньше
return
. Компилятор выдаст предупреждение, и этот код никогда не будет вызван.Что касается
return
самого себя - да, это смело можно назвать внутреннимusing
утверждением. Использование переводится как блок try-finally за сценой, и блок finally обязательно должен быть выполнен.источник
В приведенном вами примере есть проблема;
scope.Complete()
никогда не называется. Во-вторых, использованиеreturn
операторов внутриusing
операторов - не лучшая практика . См. Следующее:using(var scope = new TransactionScope()) { //have some logic here return scope; }
В этом простом примере суть в том, что; значение
scope
будет нулевым, когда оператор using будет завершен.Так что лучше не возвращаться внутрь с помощью операторов.
источник
scope
не будет нулевым - единственное , что будет произошло, чтоDispose()
будет были испробованы на этом экземпляре, и поэтому экземпляр должен не использовать больше (но не равно нулю , и нет ничего предупреждения вам попробовать и использовать удаленный объект, даже если это действительно неправильное использование одноразового объекта).return scope
вернете ссылку на этот объект. Таким образом, если вы назначаете эту ссылку при возврате, вы не позволяете GC очищать удаленный объект.Чтобы убедиться, что
scope.Complete()
функция будет вызываться, оберните ееtry/finally
.dispose
Называются , потому что вы должны обернуть его с ,using
что является альтернативойtry/finally
блока.using(var scope = new TransactionScope()) { try { // my core logic return true; // if condition met else return false; } finally { scope.Complete(); } }
источник
В этом примере scope.Complete () никогда не будет выполняться. Однако команда return очистит все, что назначено в стеке. GC позаботится обо всем, на что нет ссылок. Итак, если нет объекта, который не может быть захвачен сборщиком мусора, проблем нет.
источник