Why Did I Get the Compile Error "Use of Unassigned Local Variable"

Why did I get the compile error Use of unassigned local variable?

Local variables aren't initialized. You have to manually initialize them.

Members are initialized, for example:

public class X
{
private int _tmpCnt; // This WILL initialize to zero
...
}

But local variables are not:

public static void SomeMethod()
{
int tmpCnt; // This is not initialized and must be assigned before used.

...
}

So your code must be:

int tmpCnt = 0;  
if (name == "Dude")
tmpCnt++;

So the long and the short of it is, members are initialized, locals are not. That is why you get the compiler error.

Why does this C# code throw an error: Use of unassigned local variable 'n'

Compiler Error CS0165

The C# compiler does not allow the use of uninitialized variables. If
the compiler detects the use of a variable that might not have been
initialized, it generates compiler error CS0165. For more information,
see Fields. Note that this error is generated when the compiler
encounters a construct that might result in the use of an unassigned
variable, even if your particular code does not. This avoids the
necessity of overly-complex rules for definite assignment.

More-so, imagine this situation

int n;  

try
{
throw new Exception();
n = 123; // this code is never reached
}
catch
{
}

// oh noez!!! bam!
// The compiler is trying to be nice to you
if(n == 234);

In short, computer says no

Note : when you get a compiler error in visual studio, you can click on the error code and it sometimes (if you are lucky) gives you more concise information about what the error means

Compiler error - use of unassigned local variable. what can go wrong?

The use of an unassigned variable can be a potential bug or not (it almost always is). The question here is; if it is a bug, when would you like to know about it? At compile time or at runtime where it can be relatively hard to spot if the code is sufficiently complex or the introduced bug is subtle?

A simple example:

string Join(params object[] array)
{
string foo;

foreach (var o in arr)
foo += o.ToString();
}

So now, we have two options: the compiler lets you compile this happily and watches you crash and burn in runtime, or it tells you straightaway you have bug. The latter choice seems better to me.

Now, when you wrote this question, you were probably thinking in value types more than in reference types; an unassigned reference type is practically an immediate NullReferenceException and, although vexing, easy to fix once you run the code for the first time.

Value types on the contrary have usable default values, but that makes the situation a whole lot worse. Now maybe you forgot to initialize a variable to a sensible value and nothing apparently obvious is going wrong in runtime but maybe you've just introduced a not so obvious bug in your program:

int totalDays(DateTime date)
{
DateTime now; //TODO: initialize to server time, not local DateTime.Now
return (now - date).TotalDays;
}

Writing this code you spill your coffee, then you get a phone call from you wife telling you your dog got sick and puked on your favorite (and expensive) rug and again on the way to the vet in your brand new car... by the time you get back you've forgotten about totalDays (I finished writing it didn't I?) and you start working on other stuff in your project. By the end of the day/week, you need to meet a deadline and you ship a bug in your code. The compiler can warn you easily that something smelly is going on. Why on earth wouldn't you want it to?

Convinced?

Why compiler throw error CS0165: Use of unassigned local variable?

It's due to the compiler difference.

In this fiddle, https://dotnetfiddle.net/5GgGNS, you can see the error, which is omitted in the mono compiler.

I think the error is valid due to the fact that this line

if (myDict?.TryGetValue("hello", out var value) == true)

is not guaranteed to initialize the local variable value.

If you would rewrite it to:

if (myDict?.TryGetValue("hello", out var value) == null)

it would try to access value.

Now, the null value, or true in your case, could be a function's return value, which would only be known at run time.

But, since all variables are basically always initialized, it's just a compiler feature.

On the other hand, according to the C#5 specs:

A local variable introduced by a local-variable-declaration is not automatically initialized and thus has no default value. For the purpose of definite assignment checking, a local variable introduced by a local-variable-declaration is considered initially unassigned. A local-variable-declaration may include a local-variable-initializer, in which case the variable is considered definitely assigned only after the initializing expression (§5.3.3.4).

But your code is C# 6.

So my conclusion is that the compilers interpret it differently. The Microsoft compiler takes the ?. operator into account. You should file it as a bug, or finding at least, maybe even at both parties.


Argumentation

Fun fact, if you use this code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

class Program
{
static void Main()
{
//Your code goes here
Dictionary<string,int> myDict = null;

if (myDict?.TryGetValue("hello", out var value) == null)
{
Console.WriteLine("Hello" + value.ToString());
}
}
}

[using https://www.jdoodle.com/compile-c-sharp-online , mono 5.10.1]

You'll see the actual initialization to default(T) at work. The output is Hello0. Nevertheless, it's remarkable because due to the ?, and the fact that myDict is null, TryGetValue shouldn't be called and leaving value "uninitialized".

The null-conditional operators are short-circuiting. That is, if one operation in a chain of conditional member or element access operations returns null, the rest of the chain doesn't execute.

source

But..., since there are no uninitialized variables; if it compiles, the compiler will make sure it's behavior is not undefined.


So, since value is initialized, on run-time, the question remains if it's a valid compiler error at build time. Regarding to the run-time intend of the code it is (and that's why the error was there in the first place), but I think it remains a grey area.

Do note that according to this default(T) is not override-able, which would actually lead to no condition where it fails.


By running this little test:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

class Program
{
static void Main()
{
//Your code goes here
Dictionary<string,int> myDict = null;

if (myDict?.Bar(out var test) == null)
{
Console.WriteLine("does hit");
}
}
}

static class Foo
{
public static object Bar(this Dictionary<string,int> input, out int test)
{
test = 3;
Console.WriteLine("does not hit");
return 1;
}
}

[using https://www.jdoodle.com/compile-c-sharp-online , mono 5.10.1]

The output becomes:

does hit

And you can verify the correct run-time behavior of the ?. operator.

C# compile error Use of unassigned local variable

You need to assign both variables before you use them, and a best-practice in C# is to assign variables on the line you declare them, if you can.

So it should look something like:

  string dataFilesLocation = Dts.Variables["User::FolderPath"].Value.ToString();
string[] dataFiles = System.IO.Directory.GetFiles(dataFilesLocation);

What is the reason for Use of unassigned local variable error?

Because local variables aren't initialized by default. You should initialized them explicitly. It is a compiler feature to avoid future mistakes. It is clarified in language specification here and here.

The reason this is illegal in C# is because using an unassigned local
has high likelihood of being a bug

If you want to know the reason for this decision see here.

What does Use of unassigned local variable mean?

The compiler isn't smart enough to know that at least one of your if blocks will be executed. Therefore, it doesn't see that variables like annualRate will be assigned no matter what. Here's how you can make the compiler understand:

if (creditPlan == "0")
{
// ...
}
else if (creditPlan == "1")
{
// ...
}
else if (creditPlan == "2")
{
// ...
}
else
{
// ...
}

The compiler knows that with an if/else block, one of the blocks is guaranteed to be executed, and therefore if you're assigning the variable in all of the blocks, it won't give the compiler error.

By the way, you can also use a switch statement instead of ifs to maybe make your code cleaner.



Related Topics



Leave a reply



Submit