tags:

views:

230

answers:

6

I'd like to know if it is possible to get the return value of a function inside a finally block.

I have some code that is like this.

try
{
    return 1;
}
finally
{
    //Get the value 1
}

I know it's possible by adding a variable that can hold the returned value. But I was wondering if it was possible to get the value in any way.

Thanks

+20  A: 

No, you can't do that.

David Morton
What else can be said?
ChaosPandion
+7  A: 
int value = -1;

try 
{ 
    value = 1; 
} 
finally 
{ 

    // Now the value is available
} 

return value;
duffymo
Yes, I know it's possible that way. I was just wondering if it was possible without a variable.
Patrick Parent
this way one loses the benefits of early returns :-(
Vlad
Early return? Not sure what you mean @Vlad. That is effectively what the compiler will unwind the statement into anyways. Are you talking about from a visual flow standpoint?
GrayWizardx
@David: at least those who believe that early returns are a Good Thing would be unable to use their favourite techniques in this case.
Vlad
@Vlad: It is still possible to return early. (see my answer)
Zach Johnson
@GrayWizardx: I am talking about the code like that:`try { foreach (element in list) if (element is good) return element; /* other code */ } finally { ... };`.Without early returns you would need to write it as`try { foreach (element in list) if (element is good) { value = element; flag = true; break; } if (!flag) { /* other code with assignment to value */ } } finally { ... }; return value;`
Vlad
@Zach: indeed, simple and clever, thanks!
Vlad
@Vlad, I understood your statement in general (and I would suggest @Zach's code below) but not in this example. Thanks for the clarification.
GrayWizardx
+3  A: 

If you want to use the variable approach and return early, you could do something like this:

int Method()
{
    int @return = -1;
    try
    {
        @return = -2;
        return @return;
    }
    finally
    {
        // do something with @return
    }
}
Zach Johnson
Or more succinctly: `return @return = -2;`
Jeffrey L Whitledge
i gotta ask - what does '@' in font of variable name mean?
pm100
and for Jeffrey comment return @return = -2. WOuld that work? Which gets done first , the finally or the return
pm100
@pm100: Its escapes the keyword 'return' (see http://msdn.microsoft.com/en-us/library/aa664670%28VS.71%29.aspx). The finally will happen after the return.
Zach Johnson
Nicely done. I havent seen the @ escaping accept in the IronPython/IronRuby source code, I didnt realize it was used regularly outside of that.
GrayWizardx
But surely the use of @ escaping of reserved words to get variable names could not be considered good practice?
Nij
@Nij: I actually never really use @ to escape keywords, but I thought it was appropriate for this example.
Zach Johnson
+2  A: 

VB.Net allows you to do this:

Public Function GetValue() As Integer
    Try
        GetValue = 2
    Catch
        'Something happens
    Finally
        'Do something with GetValue
    End Try
End Function

Which tells you a little bit about what the JIT compiler is going to do.

marr75
That seems a little dangerous. Wouldn't checking the GetValue in the finally block initiate a recursive call?
JohnFx
I haven't used VB.Net very much, but I think the parenthesis are required to do a recursive function call, so this should be safe.
Jeffrey L Whitledge
This isn't recursive. GetValue (the function name) is an available variable in vb.net. Notice there's not Return statement. When the program reaches the end of the function, the GetValue is returned (in this example, 2).
marr75
A: 

I think the actual question is - can I systematically trace the exit (and entry?) of various functions - presumably for tracing / troubleshooting etc. How about aspect.net. This lets you insert code dynamically into things

pm100
Well it's not really the question. I was looking for that part only to not have to create a function and set it before returning the value. The tracing is only a small part of the project to see the time that each functions takes (It's a webservice, so we want to make sure the performance are still there).
Patrick Parent
+2  A: 

As others already mentioned, you have to use a variable in this case. However, you can wrap this behavioral pattern into a reusable method using C# 3.0 lambda functions:

static T TryFinally<T>(Func<T> body, Action<T> finallyHandler) { 
  T result = default(T);
  try {
    result = body();
  } finally {
    finallyHandler(result);
  }
  return result;
}

The TryFinally method allows you to write what you originally needed without repeating the pattern:

TryFinally(() => { 
    // body of the method
    return 1; 
  }, result => {
    // do whatever you need with 'result' here
  });
Tomas Petricek
That's not too bad.
ChaosPandion