Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moving "if" statement condition to a local variable makes C# compiler unhappy

Could you please explain me the reason of the following situation.

Today I wrote the code (only variables names are changed):

private void Foo() 
{
    int firstInteger, secondInteger;
    const string firstStringValue = "1", secondStringValue = "2";

    if (!string.IsNullOrWhiteSpace(firstStringValue) && int.TryParse(firstStringValue, out firstInteger) &&
        !string.IsNullOrWhiteSpace(secondStringValue) && int.TryParse(secondStringValue, out secondInteger))
    {
        // Using firstInteger and secondInteger here
        firstInteger++;
        secondInteger++;
    }
}

Everything was fine until I decided to move the if condition to a variable:

private void Foo()
{
    int firstInteger, secondInteger;
    const string firstStringValue = "1", secondStringValue = "2";

    bool firstIntegerAndSecondIntegerAreSpecified = 
        !string.IsNullOrWhiteSpace(firstStringValue) && int.TryParse(firstStringValue, out firstInteger) &&
        !string.IsNullOrWhiteSpace(secondStringValue) && int.TryParse(secondStringValue, out secondInteger);

    if (firstIntegerAndSecondIntegerAreSpecified)
    {
        // Use firstInteger and secondInteger here
        firstInteger++;
        secondInteger++;
    }
}

Now the compiler underlines firstInteger and secondInteger variables with error "Local variable might not be initialized before accessing".

But why? The only thing I made is refactored the code a bit. And as I see it the logic is the same.

like image 213
Maxim Timofeev Avatar asked Mar 18 '11 21:03

Maxim Timofeev


2 Answers

The compiler (or rather, the specification) doesn't spot the relationship between the value of firstIntegerAndSecondIntegerAreSpecified and the calls to int.TryParse. In the first form, it could work out that execution would only enter the body if both calls to int.TryParse had executed, and therefore both had definitely assigned values (due to the out parameters). Therefore there was no problem in the if block.

The rules for definite assignment don't cover the idea that firstIntegerAndSecondIntegerAreSpecified will only be true if both calls have been made, therefore in the body of the if block, the variables still aren't definitely assigned, hence the error.

like image 54
Jon Skeet Avatar answered Sep 19 '22 18:09

Jon Skeet


The compiler is not built to be clever enough to figure out that a true value in the boolean variable ensures that the values in the integer are set. The compiler only tracks execution paths, not varaible values.

In the first case the compiler knows that it's impossible to enter the if statement without the TryParse calls setting the variables. In the second case the if statement is detached from the TryParse calls, so the compiler would have to track the variable value to figure out the relation.

like image 32
Guffa Avatar answered Sep 20 '22 18:09

Guffa