Search code examples
c#dynamicc#-4.0cil

Why does this (null || !TryParse) conditional result in "use of unassigned local variable"?


The following code results in use of unassigned local variable "numberOfGroups":

int numberOfGroups;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
    numberOfGroups = 10;
}

However, this code works fine (though, ReSharper says the = 10 is redundant):

int numberOfGroups = 10;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
    numberOfGroups = 10;
}

Am I missing something, or is the compiler not liking my ||?

I've narrowed this down to dynamic causing the issues (options was a dynamic variable in my above code). The question still remains, why can't I do this?

This code doesn't compile:

internal class Program
{
    #region Static Methods

    private static void Main(string[] args)
    {
        dynamic myString = args[0];

        int myInt;
        if(myString == null || !int.TryParse(myString, out myInt))
        {
            myInt = 10;
        }

        Console.WriteLine(myInt);
    }

    #endregion
}

However, this code does:

internal class Program
{
    #region Static Methods

    private static void Main(string[] args)
    {
        var myString = args[0]; // var would be string

        int myInt;
        if(myString == null || !int.TryParse(myString, out myInt))
        {
            myInt = 10;
        }

        Console.WriteLine(myInt);
    }

    #endregion
}

I didn't realize dynamic would be a factor in this.


Solution

  • I am pretty sure this is a compiler bug. Nice find!

    Edit: it is not a bug, as Quartermeister demonstrates; dynamic might implement a weird true operator which might cause y to never be initialized.

    Here's a minimal repro:

    class Program
    {
        static bool M(out int x) 
        { 
            x = 123; 
            return true; 
        }
        static int N(dynamic d)
        {
            int y;
            if(d || M(out y))
                y = 10;
            return y; 
        }
    }
    

    I see no reason why that should be illegal; if you replace dynamic with bool it compiles just fine.

    I'm actually meeting with the C# team tomorrow; I'll mention it to them. Apologies for the error!