How and when to use Finally after a Try?

Asked

Viewed 8,712 times

27

First I would like to know why in using the finally

What are its advantages? It really only serves for when an exit occurs from within the scope of a block try-catch, as when some return or goto inside?

  • 3

    A comment just to add the good answers that are already here. There are rare cases where Finally may not run, more properly in case of catastrophic system failures (power cut, out of memory). Keep this in mind and don’t assume that all code in Finally is guaranteed. (In a more playful tone) See this example (http://thedailywtf.com/Articles/My-Tales.aspx)

6 answers

23


Other answers have already answered the most important question. Complementing, the most common use for the finally is the cleaning of resources.

When you use a variable declaration with using is actually using a try-finally

So when does:

using (Font font1 = new Font("Arial", 10.0f)) {
    byte charset = font1.GdiCharSet;
}

Is the same as:

{
  Font font1 = new Font("Arial", 10.0f);
  try {
    byte charset = font1.GdiCharSet;
  }
  finally {
    if (font1 != null)
      ((IDisposable)font1).Dispose();
  }
}

In fact it’s just syntax sugar. The compiler actually changes the using by the second construction.

The catch is used to capture exceptions and only, the finally is executed at all times after the end of a code block within the try or catch, if there is one, with or without exception. The finally will be executed anyway, even if before he has a return or goto trying to avoid it. It is not possible to exit the code block started by try without going through the finally (at least not under normal C#conditions, as well recalled by Omni, there are catastrophic situations that CLR may not guarantee the execution of finally, in addition, in theory it is possible to change the IL to avoid it, but this is something wrong to do).

There’s no way to use one return or goto within a finally. Or you use in the try or in the catch or place it after the finally. Remembering that if you’re after the block finally, it may not be executed, as well demonstrated by the last code of Lucas Nunes' reply.

I found this excellent response (see also the answer from Jon Skeet) showing how the return in the block protected by try. This code:

static int Test() {
    try {
        return SomeNumber();
    } finally {
        Foo();
    }
}

Compile for the CIL:

.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
}

That would be the same as:

private static int Test()
{
    int CS$1$0000;
    try
    {
        CS$1$0000 = SomeNumber();
    }
    finally
    {
        Foo();
    }
    return CS$1$0000;
}

The return is executed at the end, but the expression contained in it runs where the return in the original code.

I put in the Github for future reference.

  • +1 by reference to non-normal exit conditions.

15

You must use finally to finalize/release resources you may have used in a try, even if an exception is made, the code in the finally will be executed.

The operation is basically this:

try
{
     // seu código
}
catch
{
     // exceção 
}
finally
{
     // sempre faz isso
}

For example:
Suppose you open a file on try, but there is an exception. In finally is the right place for you to close the file.

 String path = @"arquivo_qualquer.dat";
 System.IO.StreamReader file = new System.IO.StreamReader(path);
 char[] buffer = new char[10];

 try
 {
     file.ReadBlock(buffer, index, buffer.Length);
 }
 catch (System.IO.IOException e)
 {
     Console.WriteLine("Erro de leitura em: {0}. Mensagem = {1}", path, e.Message);
 }
 finally
 {
     if (file != null)
     {
         file.Close();
     }
 }

Note that the above code is different from:

String path = @"arquivo_qualquer.dat";
System.IO.StreamReader file = new System.IO.StreamReader(path);
char[] buffer = new char[10];

try
{
    file.ReadBlock(buffer, index, buffer.Length);
}
catch (System.IO.IOException e)
{
    Console.WriteLine("Erro de leitura em: {0}. Mensagem = {1}", path, e.Message);
}

if (file != null)
{
    file.Close();
}

In this second case there is no guarantee that file will be closed, while in the first there is. The example below illustrates this, where the return in the catch prevents the last lines of the programme from being executed, but finally evening.

static void Main(string[] args)
{
    string str = "1000";
    Object obj = str;
    int numero = 0;

    try
    {
        // Essa conversão falhará.
        numero = (int)obj;

        Console.WriteLine("Essa linha não será executada.");
    }
    catch (System.Exception e)
    {
        Console.WriteLine("A conversão falhou.");

        // Esse return fará com que o último WriteLine não seja executado.
        return;
    }
    finally
    {
        Console.WriteLine("Essa linha sempre será executada.");
    }

    Console.WriteLine("Aparentemente essa linha seria executada.");
}

7

The finally only serves for use together with a try/catch.

Its use is indicated for a block situation try where, if successful or failed, the code will always be executed. This is useful for object relocation, log audit of some information, or some code that is essential for execution.

Just like the catch, the block finally is optional.

It is not necessary to use it to return some value. It can be used, but is not required.

Use:

try 
{
    /* Aqui fica o código propenso a algum erro */
} 
catch (Exception ex)
{
    /* Aqui é executado quando alguma exceção acontece */
} 
finally 
{
    /* Independente de ter caído ou não no catch, este trecho sempre executa */
}

Reference: http://msdn.microsoft.com/pt-br/library/zwc8s4fz.aspx

6

The code inside a block finally will run regardless whether or not there is an exception. This is useful when it comes to certain functions in which you need to do closing connections, disconnect or release an object.

try
{
    FazerAlgumaCoisa();
}
catch
{
    CapturarAlgo();
}
finally
{
    SempreFazerIsso();
} 

You could be doing this:

try
{
    FazerAlgumaCoisa();
}
catch
{
    CapturarAlgo();
}

SempreFazerIsso();

In the last code, the call SempreFazerIsso() will not be executed if the code within the instruction catch issue a return or launch a new exception.

Source

4

"Finally" is very useful when you open a database connection and, before closing it, decide to use a "Try catch()". You can close this same connection within Finally, so you ensure that the connection will be closed.

2

Another case where you can use Finally after Try/catch, is in the situation of manipulating files in the middle of your process and not to fill the code with File.Delete, you can just clear the folder in Finally or still save the paths and names in a variable and clear before leaving.

  • 1

    Other case? You can only use it after one try/catch.

  • 1

    Kyllopardiun, what I meant, was to demonstrate a case of using Try/catch/Finally - in order to control errors and fire emails from Exception. Clearly, the Finally is after a Try/catch.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.