Setting Return statement to Null in the finally block.

For example, If x is a local variable, will be effectively set to null anyway when the method is exited and the value of the return value is not null.

The finally statement is executed, but the return value isn’t affected. The execution order is:

  1. Code before return statement is executed
  2. Expression in return statement is evaluated
  3. finally block is executed
  4. Result evaluated in step 2 is returned

It is important to note objects and other reference types behave similarly when returned but do have some differences.

The “What” that gets returned follows the same logic as simple types:

class Test {
    public static Exception AnException() {
        Exception ex = new Exception("Me");
        try {
            return ex;
        } finally {
            // Reference unchanged, Local variable changed
            ex = new Exception("Not Me");
        }
    }
}

The reference that is being returned has already been evaluated before the local variable is assigned a new reference in the finally block.

The execution is essentially:

class Test {
    public static Exception AnException() {
        Exception ex = new Exception("Me");
        Exception CS$1$0000 = null;
        try {
            CS$1$0000 = ex;
        } finally {
            // Reference unchanged, Local variable changed
            ex = new Exception("Not Me");
        }
        return CS$1$0000;
    }
}

The difference is it would still be possible to modify mutable types using the properties/methods of the object which can result in unexpected behaviors if you are not careful.

class Test2 {
    public static System.IO.MemoryStream BadStream(byte[] buffer) {
        System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer);
        try {
            return ms;
        } finally {
            // Reference unchanged, Referenced Object changed
            ms.Dispose();
        }
    }
}

A second thing to consider about try-return-finally is that parameters passed “by reference” can still be modified after the return. Only the return value has been evaluated and is stored in a temporary variable waiting to be returned, any other variables are still modified the normal way. The contract of an out parameter can even go unfulfilled until the finally block this way.

class ByRefTests {
    public static int One(out int i) {
        try {
            i = 1;
            return i;
        } finally {
            // Return value unchanged, Store new value referenced variable
            i = 1000;
        }
    }

    public static int Two(ref int i) {
        try {
            i = 2;
            return i;
        } finally {
            // Return value unchanged, Store new value referenced variable
            i = 2000;
        }
    }

    public static int Three(out int i) {
        try {
            return 3;
        } finally {
            // This is not a compile error!
            // Return value unchanged, Store new value referenced variable
            i = 3000;
        }
    }
}

Like any other flow construct “try-return-finally” has its place and can allow for cleaner looking code than writing the structure it actually compiles to. But it must be used carefully to avoid gotcha’s.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s