Slavomír Današ
Slavomír Današ

Reputation: 85

Local variable might not be initialized before accessing - after calling .TryParse()

I have this piece of code:

var kv = new Dictionary<int, string>() { ... };

var kv30Valid = kv.ContainsKey(30) && int.TryParse(kv[30], out var kv30Value);

myObject.nullableInt = kv30Valid ? (int?)kv30Value : null;

Note: myObject is a POCO class representing a table row, that's why nullable int.

I cannot compile my code because I get compiler error on the last line:

Local variable 'kv30Value' might not be initialized before accessing

In which case can it be unintialized and how to properly handle the case to allow valid code?

I need to populate the myObject properties with values from the kv (if they are present) parsed to their respective values.

Solution: Moving the condition into TryParse() method solved the problem.

var kv30Valid = int.TryParse(kv.ContainsKey(30) ? kv[30] : null, out var kv30Value);

Upvotes: 1

Views: 1832

Answers (2)

CodeCaster
CodeCaster

Reputation: 151594

In which case can it be unintialized

When kv.ContainsKey(30) returns false, int.TryParse() isn't called, and kv30Value won't be assigned.

To simplify the issue, you have an unassigned variable:

bool test; // declared, but not assigned
if (test)
{
    Console.WriteLine("Test is true");
}

This won't compile, because test is not assigned.

Now a method with an out parameter will definitely assign the variable:

bool test;
Assign(out test);

if (test)
{
    Console.WriteLine("Test is true");
}

private static void Assign(out bool foo)
{
    foo = true;
}

This will print "Test is true".

Now if you make the assignment conditional:

bool test;

bool condition = DateTime.Now > DateTime.Now;
if (condition)
{
    Assign(out test);
}

if (test) { ... }

You'll be back at the compiler error:

CS0165: Use of unassigned local variable test

Because the assignment of test can't be guaranteed by the compiler, so it forbids further use of that variable.

Even if the usage of the variable uses the same condition:

bool test;

bool condition = DateTime.Now > DateTime.Now;
if (condition)
{
    Assign(out test);
}

if (condition && test)
{
    Console.WriteLine("Test is true");
}

Then still the compiler refuses you to use test.

That's exactly the same as with your && int.TryParse(..., out) code. The right side of the && is conditionally executed, thus the compiler will refuse to let you use the variable that's potentially unassigned.

Regarding the discussion below and the downvote on my answer, if you want to know the why behind all this, see the C# language specification chapter 5.3 Definite assignment. Basically put, you get this error because the compiler does a best effort attempt at statically analyzing whether the variable is assigned.

how to properly handle the case to allow valid code?

Declare it above, and assign it a sensible default value:

int kv30Value = 0;
var kv30Valid = kv.ContainsKey(30) && int.TryParse(kv[30], out kv30Value);

Or simplify the code by moving it into an if, where it'll be definitely assigned:

if (kv.ContainsKey(30) && int.TryParse(kv[30], out var kv30Value))
{
    myObject.nullableInt = kv30Value;
}

Upvotes: 1

Damien_The_Unbeliever
Damien_The_Unbeliever

Reputation: 239664

The definite assignment analyzer has limitations (as it must, yada yada yada halting problem, etc). Although we can look at this code and conclude that it'll only access kv30value if ContainsKey returned true and thus TryParse was called, it's too "separate" for the analyzer to be able to see this.

If this was inside an if block using kv30valid it might be able to see it but even then I'm not sure.

Upvotes: 4

Related Questions