Search code examples
c#finally

Why is my finally block not working in C#?


I've been helping a colleague debug some strange behavior in their code. The following sample illustrates this:

static void Main(string[] args)
{
    string answer = Sample();
    Console.WriteLine(answer);
}

public static string Sample()
{
    string returnValue = "abc";

    try 
    {
         return returnValue;
    }

    catch (Exception)
    {
         throw;
    }

    finally
    {
         returnValue = "def";
    }
}

What does this sample return?

You'd think that because of the finally block, it returns "def" but in fact, it returns "abc"? I've stepped through the code and confirmed that the finally block is in fact invoked.

The real answer is that you shouldn't write code like this in the first place but I'm still puzzled as to the behaviour.

Edit: To clarify the flow based on some of the answers.

When you step through the code, the finally is executed before the return.

Duplicate of: What really happens in a try { return x; } finally { x = null; } statement?


Solution

  • Yes, the finally block runs after the function returns, but this doesn't matter. Remember that the return value is passed by value, so a new temporary variable is created for it at return time, thus the finally block does nothing to affect the actual return value. If you want to support the desired behavior you could use an out parameter, like so:

    static void Main(string[] args)
    {
        string answer;
        Sample(out answer);
        Console.WriteLine(answer);
    }
    
    public static void Sample(out string answer)
    {
    
        try
        {
            answer = "abc";
            return;
        }
    
        catch (Exception)
        {
            throw;
        }
    
        finally
        {
            answer = "def";
        }
    }
    

    Or, you could simply move the return statement outside of the try block, like so:

    static void Main(string[] args)
    {
        string answer = Sample();
        Console.WriteLine(answer);
    }
    
    public static string Sample()
    {
        string returnValue;
        try
        {
            returnValue = "abc";
        }
    
        catch (Exception)
        {
            throw;
        }
    
        finally
        {
            returnValue = "def";
        }
    
        return returnValue;
    }
    

    However, given that the finally block will always override the return value, this is a questionable design.