Tuesday 14 May 2013

Handling unassigned local variable errors with struct objects in C#

Handling non assigned struct objects in C#

If you have ever used structs and had use of unassigned local variable errors from your editor i.e Visual Studio then there is a simple solution.

The problem comes about because the compiler is not clever enough to realise that the struct object will always be initialised when used.

This is usually because the struct object is initialised within an IF statement or other code branch which makes the compiler believe that a similar situation to the "unreachable code" error has been detected.

As the compile cannot definitely tell that the struct object will always be initialised when it gets used it will raise a compile error.

In Visual Studio it will usually show up with a red line under the code in question with the error message "use of unassigned local variable ..."

Here is a simple example where the struct object is populated with a method and starts off in the main constructor method unassigned.

However because of the nature of the code and the fact that on the first loop iteration oldID will never be the same as currentID (as oldID starts off as 0 and currentID as 1) then the IF statement will always cause the this.FillObject method to run on each iteration.

Therefore the myvar variable which is based on a struct called myStructObj will always get populated with new values from the loop.

However the compiler cannot tell this from the code and will raise the "use of unassigned local variable myvar" error when I try to pass the object as a parameter into the this.OutputObject(myvar) method which just outputs the current property values from the object.
public class Test
{

 /* example of a method that believes the struct object won't get assigned even though due to the if statement it always will */
 public void Test()
 {

  myStructObj myvar;
  int oldID = 0; 

  /* just a basic loop from 1 to 9 */
  for(int currentID = 1; currentID < 10; currentID++)
  {
   /* as the oldID starts as 0 and currentID starts as 1 on the first loop iteration we will always populate the struct object with values */
   if(oldID != currentID)
   {
    /* populate our struct object using our FillObject method */
    myvar = this.FillObject(currentID, "ID: " + currentID.ToString());

    oldID = currentID;
   }

   /* try and parse our struct to a method to output the values - this is where we would get our red line under the myvar parameter being passed into the OutputObject method e.g. "use of unassigned local variable myvar" */
   this.OutputObject(myvar);
  }

 }

 /* Simple method to output the properties of the object to the console */
 private void OutputObject(myStructObj myvar)
 {
  Console.WriteLine(myvar.prop1);
  Console.WriteLine(myvar.prop2);
 }

 /* Simple method to populate the struct object with a string and integer value for both properties*/
 private myStructObj FillObject(string val1, int val2)
 {
  myStructObj myvar = new myStructObj();

  myvar.prop1 = val1;
  myvar.prop2 = val2;

  return myvar;
 }

 /* my struct object definition - using non nullable types */
 public struct myStructObj
 {
  public string prop1;

  public int prop2;
 }
}

Solution to use of unassigned local struct variable

The solution is to either to always initialise the object before you start the loop or to just use the default keyword to ensure your struct object variable is always set-up with default values.

Example Fix

myStructObj myvar = default(myStructObj);

This will get rid of those annoying red lines and use of unassigned local variable errors.

If your struct object is a value type then it calls the default constructor and if it's a reference type you will get a null that you can then test for before using it.

Simples!

No comments: