Pourquoi utiliser enfin en C #?

189

Tout ce qui est à l'intérieur des blocs finalement est exécuté (presque) toujours, alors quelle est la différence entre y inclure du code ou le laisser non fermé?

Rodrigo
la source
3
Que voulez-vous dire par le laisser non fermé?
Ramesh
5
Et qu'entendez-vous par «(presque)»?
Beska
49
Si vous débranchez le cordon d'alimentation pendant qu'une machine exécute une clause try, la clause finally ne sera pas appelée.
Dour High Arch
5
lol, oui, c'est vrai, mais vous ne pouvez pas vraiment coder pour ça, n'est-ce pas?
Ed S.
2
@Ed: utilisez des transactions. Votre clause try doit apporter une sorte de modification temporaire ou en mémoire qui peut être conservée dans une seule modification atomique dans la clause finally. Ceci est rarement facile et peut nécessiter un matériel spécial.
Dour High Arch

Réponses:

405

Le code à l'intérieur d'un bloc finally sera exécuté indépendamment du fait qu'il y ait ou non une exception. Ceci est très pratique lorsqu'il s'agit de certaines fonctions d'entretien ménager dont vous avez besoin pour toujours fonctionner comme la fermeture de connexions.

Maintenant, je suppose que votre question est de savoir pourquoi vous devriez faire ceci:

try
{
    doSomething();
}
catch
{
    catchSomething();
}
finally
{
    alwaysDoThis();
}

Quand vous pouvez faire ceci:

try
{
    doSomething();
}
catch
{
    catchSomething();
}

alwaysDoThis();

La réponse est que souvent, le code de votre instruction catch renverra une exception ou sortira de la fonction actuelle. Avec ce dernier code, le "alwaysDoThis ();" call ne s'exécutera pas si le code à l'intérieur de l'instruction catch émet un retour ou lève une nouvelle exception.

Kevin Pang
la source
3
Hmm. Très similaire à ce que j'ai dit, mais plus clair et plus exact. Définit +1.
Beska
46
cela s'applique également à "return" dans le bloc try {}.
Lucas
4
en fait, cela s'applique même sans bloc catch {} (il suffit d'essayer / enfin, laisser les exceptions bouillonner)
Lucas
mieux que le mien, était au travail et ne voulait pas passer dix minutes à y répondre en détail. +1
Matt Briggs
2
Oui, c'était exactement ce que j'avais en tête: D Maintenant je le comprends.
Rodrigo
62

La plupart des avantages de l'utilisation de try-finally ont déjà été soulignés, mais j'ai pensé ajouter celui-ci:

try
{
    // Code here that might throw an exception...

    if (arbitraryCondition)
    {
        return true;
    }

    // Code here that might throw an exception...
}
finally
{
    // Code here gets executed regardless of whether "return true;" was called within the try block (i.e. regardless of the value of arbitraryCondition).
}

Ce comportement le rend très utile dans diverses situations, en particulier lorsque vous devez effectuer un nettoyage (disposer des ressources), bien qu'un bloc d' utilisation soit souvent préférable dans ce cas.

Noldorin
la source
2
C'est littéralement la seule raison pour laquelle j'utilise enfin
Christopher Townsend
12

chaque fois que vous utilisez des requêtes de code non gérées comme des lecteurs de flux, des requêtes de base de données, etc. et vous voulez attraper l'exception, puis utilisez try catch enfin et fermez le flux, le lecteur de données, etc. enfin, si vous ne le faites pas quand il y a des erreurs, la connexion ne se ferme pas, c'est vraiment mauvais avec les requêtes db

 SqlConnection myConn = new SqlConnection("Connectionstring");
        try
        {
            myConn.Open();
            //make na DB Request                
        }
        catch (Exception DBException)
        {
            //do somehting with exception
        }
        finally
        {
           myConn.Close();
           myConn.Dispose();
        }

si vous ne voulez pas attraper l'erreur, utilisez

 using (SqlConnection myConn = new SqlConnection("Connectionstring"))
        {
            myConn.Open();
            //make na DB Request
            myConn.Close();
        }

et l'objet de connexion sera supprimé automatiquement s'il y a une erreur, mais vous ne capturez pas l'erreur

Bob le concierge
la source
2
Dispose () fermera également () la connexion, pas besoin d'appeler les deux. Close () NE Dipose PAS (), vous pouvez rouvrir la connexion.
Lucas le
Bien, merci d'avoir mentionné l'utilisation. Je devrais répondre, sinon.
Dan Rosenstark
11

Parce que finally sera exécuté même si vous ne gérez pas d'exception dans un bloc catch.

Matt Briggs
la source
7

Enfin, les instructions peuvent s'exécuter même après le retour.

private int myfun()
{
    int a = 100; //any number
    int b = 0;
    try
    {
        a = (5 / b);
        return a;
    }
    catch (Exception ex)
    {
        Response.Write(ex.Message);
        return a;
    }

 //   Response.Write("Statement after return before finally");  -->this will give error "Syntax error, 'try' expected"
    finally
    {
      Response.Write("Statement after return in finally"); // --> This will execute , even after having return code above
    } 

    Response.Write("Statement after return after finally");  // -->Unreachable code
}
Prateek Gupta
la source
7

finally, un péché:

try {
  // do something risky
} catch (Exception ex) {
  // handle an exception
} finally {
  // do any required cleanup
}

est une opportunité garantie d'exécuter du code après votre try..catch blocage, que votre bloc try ait lancé ou non une exception.

Cela le rend parfait pour des choses comme la libération de ressources, les connexions de base de données, les descripteurs de fichiers, etc.

David Alpert
la source
3
Tous ces exemples sont généralement mieux servis avec un bloc d'utilisation, mais cela n'enlève rien à votre réponse.
Joel Coehoorn
4

Je vais expliquer l'utilisation de finalement avec une exception de lecteur de fichiers Exemple

  • sans utiliser finalement
try{

  StreamReader strReader = new StreamReader(@"C:\Ariven\Project\Data.txt");
  Console.WriteLine(strReader.ReadeToEnd());
  StreamReader.Close();
}
catch (Exception ex)
{
  Console.WriteLine(ex.Message);
}

dans l'exemple ci-dessus, si le fichier appelé Data.txt est manquant, une exception sera lancée et sera traitée mais l' instruction appelée StreamReader.Close();ne sera jamais exécutée.
En raison de cela, les ressources associées au lecteur n'ont jamais été publiées.

  • Pour résoudre le problème ci-dessus, nous utilisons enfin
StreamReader strReader = null;
try{
    strReader = new StreamReader(@"C:\Ariven\Project\Data.txt");
    Console.WriteLine(strReader.ReadeToEnd());
}
catch (Exception ex){
    Console.WriteLine(ex.Message);
}
finally{
    if (strReader != null){
        StreamReader.Close();
    }
}

Bon codage :)

Remarque: "@" est utilisé pour créer une chaîne textuelle , pour éviter l'erreur de "Séquence d'échappement non reconnue". Le symbole @ signifie lire cette chaîne littéralement et n'interpréter les caractères de contrôle autrement.

Ariven Nadar
la source
2

Supposons que vous deviez redéfinir le curseur sur le pointeur par défaut au lieu d'un curseur d'attente (sablier). Si une exception est levée avant de définir le curseur et ne plante pas carrément l'application, vous pourriez vous retrouver avec un curseur déroutant.

Chris Doggett
la source
2

Parfois, vous ne voulez pas gérer une exception (pas de bloc catch), mais vous voulez que du code de nettoyage s'exécute.

Par exemple:

try
{
    // exception (or not)
}
finally
{
    // clean up always
}
Markom
la source
Si l'exception n'est pas interceptée, l'exécution du bloc finally dépend du choix du système d'exploitation de déclencher une opération de déroulement d'exception.
Vikas Verma
2

Le bloc finally est précieux pour nettoyer toutes les ressources allouées dans le bloc try ainsi que pour exécuter tout code qui doit s'exécuter même s'il y a une exception. Le contrôle est toujours passé au bloc finally quelle que soit la façon dont le bloc try se termine.

cgreeno
la source
1

Ahh ... je crois que je vois ce que tu dis! M'a pris une seconde ... vous vous demandez "pourquoi le placer dans le bloc finally au lieu après le bloc finally et complètement en dehors du try-catch-finally".

Par exemple, cela peut être dû au fait que vous arrêtez l'exécution si vous générez une erreur, mais que vous souhaitez toujours nettoyer les ressources, telles que les fichiers ouverts, les connexions à la base de données, etc.

Beska
la source
1

Le flux de contrôle du bloc Final est soit après le bloc Try ou Catch.

[1. First Code]
[2. Try]
[3. Catch]
[4. Finally]
[5. After Code]

avec Exception 1> 2> 3> 4> 5 si 3 a une instruction Return 1> 2> 3> 4

sans exception 1> 2> 4> 5 si 2 a une instruction de retour 1> 2> 4

Ranald Fong
la source
0

Comme mentionné dans la documentation :

Une utilisation courante de catch and finally est d'obtenir et d'utiliser des ressources dans un bloc try, de gérer des circonstances exceptionnelles dans un bloc catch et de libérer les ressources du bloc finally.

Cela vaut également la peine de lire ceci , qui déclare:

Une fois qu'une clause catch correspondante est trouvée, le système se prépare à transférer le contrôle vers la première instruction de la clause catch. Avant que l'exécution de la clause catch ne commence, le système exécute d'abord, dans l'ordre, toutes les clauses finally associées à des instructions try plus imbriquées que celle qui a intercepté l'exception.

Il est donc clair que le code qui réside dans une finallyclause sera exécuté même si une catchclause antérieure avait une returninstruction.

Nexaspx
la source