Non - au niveau IL, vous ne pouvez pas revenir de l'intérieur d'un bloc géré par exception. Il le stocke essentiellement dans une variable et retourne ensuite
c'est-à-dire similaire à:
int tmp;
try {
tmp = ...
} finally {
...
}
return tmp;
par exemple (à l'aide d'un réflecteur):
static int Test() {
try {
return SomeNumber();
} finally {
Foo();
}
}
se compile pour:
.method private hidebysig static int32 Test() cil managed
{
.maxstack 1
.locals init (
[0] int32 CS$1$0000)
L_0000: call int32 Program::SomeNumber()
L_0005: stloc.0
L_0006: leave.s L_000e
L_0008: call void Program::Foo()
L_000d: endfinally
L_000e: ldloc.0
L_000f: ret
.try L_0000 to L_0008 finally handler L_0008 to L_000e
}
Cela déclare fondamentalement une variable locale ( CS$1$0000
), place la valeur dans la variable (à l'intérieur du bloc manipulé), puis après avoir quitté le bloc charge la variable, puis la retourne. Reflector rend ceci comme:
private static int Test()
{
int CS$1$0000;
try
{
CS$1$0000 = SomeNumber();
}
finally
{
Foo();
}
return CS$1$0000;
}
L'instruction finally est exécutée, mais la valeur de retour n'est pas affectée. L'ordre d'exécution est le suivant:
Voici un petit programme pour démontrer:
Ceci imprime "try" (parce que c'est ce qui est retourné) puis "finalement" parce que c'est la nouvelle valeur de x.
Bien sûr, si nous renvoyons une référence à un objet mutable (par exemple un StringBuilder), toutes les modifications apportées à l'objet dans le bloc finally seront visibles au retour - cela n'a pas affecté la valeur de retour elle-même (qui est juste un référence).
la source
return
instruction, et cette valeur sera retournée. L'expression n'est pas évaluée car le contrôle quitte la méthode.La clause finally s'exécute après l'instruction return mais avant de revenir réellement de la fonction. Cela a peu à voir avec la sécurité des fils, je pense. Ce n'est pas un hack - le enfin est garanti pour toujours fonctionner, peu importe ce que vous faites dans votre bloc try ou votre bloc catch.
la source
En plus des réponses données par Marc Gravell et Jon Skeet, il est important de noter que les objets et autres types de référence se comportent de la même manière lorsqu'ils sont retournés, mais présentent quelques différences.
Le "Quoi" qui est retourné suit la même logique que les types simples:
La référence renvoyée a déjà été évaluée avant que la variable locale se voit attribuer une nouvelle référence dans le bloc finally.
L'exécution est essentiellement:
La différence est qu'il serait toujours possible de modifier les types mutables en utilisant les propriétés / méthodes de l'objet, ce qui peut entraîner des comportements inattendus si vous ne faites pas attention.
Une deuxième chose à considérer à propos de try-return-enfin est que les paramètres passés "par référence" peuvent toujours être modifiés après le retour. Seule la valeur de retour a été évaluée et est stockée dans une variable temporaire en attente de retour, toutes les autres variables sont toujours modifiées de la manière normale. Le contrat d'un paramètre de sortie peut même rester inachevé jusqu'à ce qu'il soit finalement bloqué de cette façon.
Comme toute autre construction de flux, «try-return-finally» a sa place et peut permettre un code plus propre que d'écrire la structure dans laquelle il se compile. Mais il doit être utilisé avec précaution pour éviter les pièges.
la source
Si
x
est une variable locale, je ne vois pas le point, car ilx
sera de toute façon effectivement réglé sur null lorsque la méthode sera quittée et que la valeur de la valeur de retour ne sera pas nulle (puisqu'elle a été placée dans le registre avant l'appel à setx
à null).Je ne peux voir cela se produire que si vous voulez garantir le changement de la valeur d'un champ au retour (et après que la valeur de retour est déterminée).
la source