Question

What is the defined behaviour in C# for when an exception is thrown before setting the value of an out parameter, and you then try to access the parameter?

public void DoSomething(int id, out control)
{
    try
    {
        int results = Call(Id);
        control = new CallControl(results);
    }
    catch(Exception e)
    {
      throw new Exception("Call failed", e);
    }
}

//somewhere else
DoSomething(out Control control)
{
    try
    {
       DoSomething(1, out control);
    }
    catch()
    {
    // handle exception
    }
}

// later
Control control;
DoSomething(out control)
control.Show();

The compiler normally complains about exiting the method before setting the out parameter. This seems to outsmart it from protecting me from myself.

Was it helpful?

Solution

What is the defined behaviour in C# for when an exception is thrown before setting the value of an out parameter, and you then try to access the parameter?

You can't do so. The variable will still not be definitely assigned, unless it's definitely assigned before the method call.

If the variable was definitely assigned before the method call, then it will still be definitely assigned - but unless the method assigned a value before the exception was thrown, the variable's value will remain untouched:

class Test
{
    static void JustThrow(out int x)
    {
        throw new Exception();
    }

    static void Main()
    {
        int y = 10;
        try
        {
            JustThrow(out y);
        }
        catch
        {
            // Ignore
        }
        Console.WriteLine(y); // Still prints 10
    }
}

OTHER TIPS

That's OK. If DoSomething throws, control.Show() is not executed.

You can't outsmart the compiler anyway, because it knows when the control flow could bypass the initialisation.

Consider this code, which is similar to the code you were proposing:

using System;

namespace Demo
{
    internal class Program
    {
        private void run()
        {
            int a;

            try
            {
                DoSomething(out a);
            }

            catch {} // Evil empty catch.

            Console.WriteLine(a); // Compile error.
        }

        public void DoSomething(out int x)
        {
            test();
            x = 0;
        }

        private static void test()
        {
            throw new InvalidOperationException("X");
        }

        private static void Main()
        {
            new Program().run();
        }
    }
}

It gives a compile error because you have put a try/catch around the DoSomething() and therefore the compiler assumes that a might not have been initialised.

(Note that all stack variables are initialised to their default values if you don't initialise them explicitly, but that doesn't affect the compiler's control flow analysis. The compiler cares about definite assignment, not the default initialisation that the CLR does. This initialisation is not guaranteed by the C# standard anyway.)

If you change the empty catch to one that throws, the compile error goes away:

catch { throw new Exception("Test"); } // Compile error goes away.

because now you can't reach the code that uses a if an exception occurred.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top