Je veux juste savoir est-ce une approche sûre / bonne pour appeler à l' return
intérieur d'un using
bloc.
Par ex.
using(var scope = new TransactionScope())
{
// my core logic
return true; // if condition met else
return false;
scope.Complete();
}
Nous savons que la dernière accolade la plus bouclée dispose()
sera annulée . Mais que sera-t-il dans le cas ci-dessus, puisque return
saute le contrôle hors de la portée donnée (AFAIK) ...
- Mon
scope.Complete()
être appelé? - Et il en va de même pour la
dispose()
méthode du scope .
using{}
portée terminée, les objets concernés sont éliminés,return
"briseront" la portée - de sorte que les objets seront disposés comme prévuscope.Complete()
appel ne sera jamais atteint avec l'échantillon que vous avez fourni, de sorte que votre transaction sera toujours annulée.using
sdispose()
soit appelé, lorsque vous revenez, la fonction contenant ceusing
bloc sera retournée et tout ce qui lui appartient sera orphelin. Ainsi, même si ellescope
n'avait pas été éliminée "par leusing
" (ce sera, comme d'autres l'ont expliqué), elle le sera quand même car la fonction s'est terminée. Si C # avait unegoto
déclaration, avez-vous fini de rire? bon- alors au lieu de revenir, vous pourriezgoto
après l'accolade de fermeture, sans revenir. Logiquement,scope
serait toujours disposé, mais vous venez de mettregoto
en C # alors qui se soucie de la logique à ce stade.Réponses:
Il est parfaitement sûr d'appeler à l'
return
intérieur de votreusing
bloc, car un bloc using n'est qu'untry/finally
bloc.Dans votre exemple ci-dessus après le retour
true
, la portée sera supprimée et la valeur retournée.return false
, et nescope.Complete()
sera pas appelé.Dispose
cependant sera appelé indépendamment car il réside dans le bloc finally.Votre code est essentiellement le même (si cela facilite la compréhension):
Veuillez noter que votre transaction ne sera jamais validée car il n'y a aucun moyen
scope.Complete()
de valider la transaction.la source
Dispose
serez appelé. Si le PO ne sait pas ce qui se passeusing
, il est probable qu'il ne sache pas ce qui se passefinally
.using
, par exempleusing (var callersVar = MyFunc(..)) ..
, au lieu d'avoir l'utilisation à l'intérieur de "MyFunc" - je veux dire que l'appelant reçoit le flux et est responsable de le fermer viausing
ou explicitement, ou (b) Demandez à MyFunc d' extraire toutes les informations nécessaires dans d'autres objets, qui peuvent être transmises en toute sécurité - alors les objets de données sous-jacents ou le flux peuvent être supprimés par votreusing
. Vous ne devriez pas avoir à écrire du code qui fuit.C'est très bien - les
finally
clauses (c'est ce que fait l'accolade fermante de lausing
clause sous le capot) sont toujours exécutées lorsque la portée est laissée, peu importe comment.Cependant, cela n'est vrai que pour les instructions qui se trouvent dans le bloc finally (qui ne peut pas être défini explicitement lors de l'utilisation
using
). Par conséquent, dans votre exemple,scope.Complete()
ne serait jamais appelé (je m'attends à ce que le compilateur vous avertisse du code inaccessible).la source
En général, c'est une bonne approche. Mais dans votre cas, si vous revenez avant d'appeler le
scope.Complete()
, il supprimera simplement le TransactionScope. Dépend de votre conception.Ainsi, dans cet exemple, Complete () n'est pas appelé et la portée est supprimée, en supposant qu'elle hérite de l'interface IDisposable.
la source
scope.Complete doit être appelé avant
return
. Le compilateur affichera un avertissement et ce code ne sera jamais appelé.En ce qui concerne
return
lui-même - oui, il est prudent de l'appelerusing
déclaration intérieure . L'utilisation est traduite en bloc try-finally dans les coulisses et enfin block doit être certainement exécuté.la source
Dans l'exemple que vous avez fourni, il y a un problème;
scope.Complete()
n'est jamais appelé. Deuxièmement, ce n'est pas une bonne pratique d'utiliser desreturn
instructions dans desusing
instructions. Reportez-vous à ce qui suit:Dans cet exemple simple, le point est que; la valeur de
scope
sera nulle lorsque l'instruction d'utilisation est terminée.Il vaut donc mieux ne pas retourner à l'intérieur en utilisant des instructions.
la source
scope
ne sera pas nulle - la seule chose qui se sera produite est qu'elleDispose()
aura été invoquée sur cette instance, et donc l'instance ne devrait plus être utilisée (mais elle n'est pas nulle et rien ne vous empêche d'essayer d'utiliser l'objet éliminé, même s'il s'agit bien d'une utilisation inappropriée d'un objet jetable).return scope
renvoie une référence à cet objet. De cette façon, si vous attribuez cette référence au retour, vous empêchez le GC de nettoyer l'objet éliminé.Pour vous assurer que le
scope.Complete()
sera appelé, enveloppez-le avectry/finally
. Ledispose
est appelé parce que vous l'avez enveloppé avec leusing
qui est untry/finally
bloc alternatif .la source
Dans cet exemple, scope.Complete () ne s'exécutera jamais. Cependant, la commande return nettoiera tout ce qui est assigné sur la pile. Le GC s'occupera de tout ce qui n'est pas référencé. Donc, à moins qu'il y ait un objet qui ne puisse pas être capté par le GC, il n'y a pas de problème.
la source