Question

After searching around I cant seem to locate why the C# compiler is complaining that the local variable dteDest is unassigned in the line

if (dteSrc == dteDest) {

The error goes away if I replace the line

DateTime dteSrc, dteDest;

with

DateTime dteSrc, dteDest = DateTime.MinValue;

As far as I can see the code will never reach the comparison line if dteDest is not initialised by the DateTime.TryParse which it is an out parameter for.

My logic is:

  1. If currentDataObj is null then booHaveOrigDate is false and the first if fails
  2. If currentDataObj is not null but cant be converted to a DateTime then booHaveOrigDate is false and the first if fails
  3. DateTime.TryParse will return false if it cant convert to a DateTime this along with the && means that dteDest will never be used.

Simple Sample Code

void StrangeLogic(object srcData, object currentDataObj) {
   DateTime dteSrc, dteDest;

   bool booHaveNewDate = DateTime.TryParse(srcData.ToString(), out dteSrc);
   bool booHaveOrigDate = (currentDataObj != null) 
                          && DateTime.TryParse(currentDataObj.ToString(), out dteDest);

   if (booHaveNewDate && booHaveOrigDate) {
      if (dteSrc == dteDest) { 
          // Get a "use of unassignned local variable 'dteDest' 
          // unless dteDest = DateTime.MinValue beforehand
      }
   }
}

Also if I change the line

bool booHaveNewDate = DateTime.TryParse(srcData.ToString(), out dteSrc);

to the following

bool booHaveNewDate = (srcData != null) && DateTime.TryParse(srcData.ToString(), out dteSrc);

then the compiler complains that srcDate is not assigned as well.

Could anyone point me in the right direction to what I am missing - I dont mean about parameter checking etc I am concerned with why the compiler logic seems to be fooled by the use of a common TryParse function?

Additional Info

Even expanding out the logic still gives the same error (use of unassigned local variable)

bool booHaveOrigDate;
if (currentDataObj != null) 
   booHaveOrigDate = DateTime.TryParse(currentDataObj.ToString(), out dteDest); 
else 
   booHaveOrigDate = false;

if (booHaveOrigDate) {
    if (dteSrc == dteDest) {

It appears that it is whatever the compiler does with the null checking (currentDataObj != null) that prevents it from correctly determing the dteDest wont be accessed unless assigned

Change it to this code and no problems (aside from the possible .ToString() on a null object

bool booHaveOrigDate = DateTime.TryParse(currentDataObj.ToString(), out dteDest); 
if (booHaveOrigDate) {
    if (dteSrc == dteDest) {
Was it helpful?

Solution

Your replace is incorrect, it should be:

DateTime dteSrc = DateTime.MinValue, dteDest = DateTime.MinValue;

However you should use the return variable of TryParse, which is a bool to see if tryparse worked instead if your booHaveNewDate:

DateTime dteSrc, dteDest;

if(DateTime.TryParse(srcData.ToString(), out dteSrc) && DateTime.TryParse(currentDataObj.ToString(), out dteDest))
{
  if (dteSrc == dteDest) { 
      // Do your stuff here
  }
}

Now you do not have to assign the dates in the beginning.

** You should test this code before using, it is no production code and can contain errors

OTHER TIPS

The compiler is formally correct, the assignment to dteDest (as out parameter) is conditional. In the eyes of the compiler it might not happen. The compiler doesn't 'understand' the logic that follows from TryParse().

Here is a similar situation:

int f(int x)
{
   int r;

   if (x <= 5)  r = 1;
   if (x >  5)  r = 2;

   return r;  // error: use of uninitialized var
}

On a side note, it seems slightly more logical to initialize with

  DateTime dteSrc = default(DateTime), dteDest = default(DateTime);

it is the same value (DateTime.MinValue) though.

I could be wrong but I don't think the compiler attempts to dissect your code that extensively when reporting this error. I'm currently trying to find some source to back up my theory. In the mean time, my guess would be that this is a design decision because if it takes a person more than a couple seconds to see that a variable will not be used before being initialized it's probably a better coding decision to just null initialize it to begin with in order to avoid confusion.

EDIT:

Well I did a bit of looking around and while I found a couple examples of people saying essentially the same thing I am I cannot find any official documentation stating this. Here are the responses I found though:

"The compiler is perfectly entitled to not know your logic."

http://www.pcreview.co.uk/forums/use-unassigned-local-variable-error-t3067479.html

"...when there's a control flow structure, it can't evaluate the situation, because it's not executing code, so it doesn't know if the values are getting assigned."

http://bytes.com/topic/c-sharp/answers/917965-why-am-i-getting-unassigned-local-variable-errors

dteDest will not have a value set if currentDataObj == null

It will work if you change your line to:

bool booHaveOrigDate = DateTime.TryParse(currentDataObj != null ? currentDataObj.ToString() : string.Empty, out dteDest);

compiler logic seems to be fooled by the use of a common TryParse function

The question above can be most easily answered by the fact that when the compiler is compiling your code it doesn't look at what that method is doing internally, it just looks at the signature. It knows it can return a boolean that may be true or false and it knows that it is setting the value of dteDest.

This isn't really your problem though. The problem comes in that the following line:

bool booHaveOrigDate = (currentDataObj != null) 
          && DateTime.TryParse(currentDataObj.ToString(), out dteDest);

Uses the && operator which will not evaluate the second part if the first part is false. This is called short circuit evaluation and works on the theory that if the first part is false then it doesn't matter what the second part is - the overall result will always be false.

So in this case dteDest is never being set and the compiler feels this is a problem, even if you look at the logic and say that the code will never run if it is not set.

The simple fact is that people can often spot optimisation and special cases that are beyond the compiler. You sound like you are already aware that you can solve this simply just by checking the parameter at the beginning and then returning if its null.

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