Value cannot be null, ArgumentNullException

Wooolie picture Wooolie · Oct 31, 2013 · Viewed 21.7k times · Source

I am currently trying to return an array which contains information about a seat at a theate such as Seat number, Name, Price and Status. I am using a combobox where I want to list all vacant or reserved seats based upon choice. When I choose reserved seats in my combobox, I call upon a method using AddRange. This method is supposed to loop through an array containing all seats and their information. If a seat is Vacant, I add it to an array. When all is done, I return this array. However, I am dealing with a ArgumentNullException.

MainForm:

namespace Assignment4
{
   public partial class MainForm : Form
   {
      // private const int totNumberOfSeats = 240;
      private SeatManager seatMngr; 
      private const int columns = 10;
      private const int rows = 10;

      public enum DisplayOptions
      {
         AllSeats,
         VacantSeats,
         ReservedSeats
      }

      public MainForm()
      {
         InitializeComponent();

         seatMngr = new SeatManager(rows, columns);
         InitializeGUI();
      }

      /// <summary>
      /// Fill the listbox with information from the beginning, 
      /// let the user be able to choose from vacant seats.
      /// </summary>
      private void InitializeGUI()
      {
         rbReserve.Checked = true;
         txtName.Text = string.Empty;
         txtPrice.Text = string.Empty;

         lblTotalSeats.Text = seatMngr.GetNumOfSeats().ToString();

         cmbOptions.Items.AddRange(Enum.GetNames(typeof(DisplayOptions)));
         cmbOptions.SelectedIndex = 0;

         UpdateGUI();
      }

      /// <summary>
      /// call on methods ValidateName and ValidatePrice with arguments
      /// </summary>
      /// <param name="name"></param>
      /// <param name="price"></param>
      /// <returns></returns>
      private bool ValidateInput(out string name, out double price)
      {
         bool nameOK = ValidateName(out name);
         bool priceOK = ValidatePrice(out price);

         return nameOK && priceOK;
      }

      /// <summary>
      /// Validate name using inputUtility, show error if input is invalid
      /// </summary>
      /// <param name="name"></param>
      /// <returns></returns>
      private bool ValidateName(out string name)
      {
         name = txtName.Text.Trim();

         if (!InputUtility.ValidateString(name))
         {
            //inform user
            MessageBox.Show("Input of name is Invalid. It can not be empty, " +   Environment.NewLine + "and must have at least one character.", " Error!");

            txtName.Focus();
            txtName.Text = " ";
            txtName.SelectAll();
            return false;
         }
         return true;
      }

      /// <summary>
      /// Validate price using inputUtility, show error if input is invalid
      /// </summary>
      /// <param name="price"></param>
      /// <returns></returns>
      private bool ValidatePrice(out double price)
      {
         // show error if input is invalid
         if (!InputUtility.GetDouble(txtPrice.Text.Trim(), out price, 0))
         {
            //inform user
            MessageBox.Show("Input of price is Invalid. It can not be less than 0, " + Environment.NewLine + "and must not be empty.", " Error!");

            txtPrice.Focus();
            txtPrice.Text = " ";
            txtPrice.SelectAll();
            return false;
         }
         return true;
      }

      /// <summary>
      /// Check if item is selected in listbox
      /// </summary>
      /// <returns></returns>
      private bool CheckSelectedIndex()
      {
         int index = lbSeats.SelectedIndex;
         if (index < 0)
         {
            MessageBox.Show("Please select an item in the box");
            return false;
         }
         else
            return true;
      }

      /// <summary>
      /// Call method ReserveOrCancelSeat when button OK is clicked
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void btnOK_Click(object sender, EventArgs e)
      {
         ReserveOrCancelSeat();
      }

      /// <summary>
      /// Reserve or cancel seat depending on choice the user makes. Update GUI after choice.
      /// </summary>
      private void ReserveOrCancelSeat()
      {
         if (CheckSelectedIndex() == true)
         {
            string name = string.Empty;
            double price = 0.0;
            int selectedSeat = lbSeats.SelectedIndex;
            bool reserve = false;
            bool cancel = false;

            if (rbReserve.Checked)
            {
               DialogResult result = MessageBox.Show("Do you want to continue?", "Approve", MessageBoxButtons.YesNo);
               if (result == DialogResult.Yes)
               {
                  if (ValidateInput(out name, out price))
                  {
                     reserve = seatMngr.ReserveSeat(name, price, selectedSeat);
                     if (reserve == true)
                     {
                         MessageBox.Show("Seat has been reserved");
                         UpdateGUI();
                     }
                     else
                     {
                        MessageBox.Show("Seat has already been reserved");
                     }
                  }
               }
            }
            else
            {
               DialogResult result = MessageBox.Show("Do you want to continue?", "Approve", MessageBoxButtons.YesNo);
               if (result == DialogResult.Yes)
               {
                  cancel = seatMngr.CancelSeat(selectedSeat);
                  if (cancel == true)
                  {
                     MessageBox.Show("Seat has been cancelled");
                     UpdateGUI();
                  }
                  else
                  {
                     MessageBox.Show("Seat is already vacant");
                  }
               }
            }
            UpdateGUI();
         }
      }

      /// <summary>
      /// Update GUI with new information. 
      /// </summary>
      /// <param name="customerName"></param>
      /// <param name="price"></param>
      private void UpdateGUI()
      {
         lbSeats.Items.Clear();
         lbSeats.Items.AddRange(seatMngr.GetSeatInfoString());
         lblVacantSeats.Text = seatMngr.GetNumOfVacant().ToString();
         lblReservedSeats.Text = seatMngr.GetNumOfReserved().ToString();

         if (rbReserve.Checked)
         {
            txtName.Text = string.Empty;
            txtPrice.Text = string.Empty;
         }
      }

      /// <summary>
      /// set textboxes to false if cancel reservation button is checked
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void rbCancel_CheckedChanged_1(object sender, EventArgs e)
      {
         txtName.Enabled = false;
         txtPrice.Enabled = false;
      }

      /// <summary>
      /// set textboxes to true if reserved radiobutton is checked
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void rbReserve_CheckedChanged_1(object sender, EventArgs e)
        {
            txtName.Enabled = true;
            txtPrice.Enabled = true;
        }

        /// <summary>
        /// Make necessary changes on the list depending on what choice the user makes. Show only 
        /// what the user wants to see, whether its all seats, reserved seats or vacant seats only.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbOptions_SelectedIndexChanged(object sender, EventArgs e)
        {
           if (cmbOptions.SelectedIndex == 0 && rbReserve.Checked) //All seats visible.
           {
              UpdateGUI();
              txtName.Enabled = true;
              txtPrice.Enabled = true;
              btnOK.Enabled = true;
           }
           else if (cmbOptions.SelectedIndex == 0 && rbCancel.Checked)
           {
              UpdateGUI();
              txtName.Enabled = false;
              txtPrice.Enabled = false;
              btnOK.Enabled = true;
           }

           else if (cmbOptions.SelectedIndex == 1) //Only vacant seats visible.
           {
              lbSeats.Items.Clear();
              lbSeats.Items.AddRange(seatMngr.ReturnVacantSeats()); // Value cannot be null
              txtName.Enabled = false;
              txtPrice.Enabled = false;
              btnOK.Enabled = false;
           }

           else if (cmbOptions.SelectedIndex == 2) //Only reserved seats visible.
           {
              lbSeats.Items.Clear();
              lbSeats.Items.AddRange(seatMngr.ReturnReservedSeats()); // Value cannot be null
              txtName.Enabled = false;
              txtPrice.Enabled = false;
              btnOK.Enabled = false;
           }
        }
    }
}

SeatManager:

namespace Assignment4
{
   class SeatManager
   {
      private string[,] nameList = null;
      private double[,] priceList = null;
      private string[,] seatList = null;
      private readonly int totCols;
      private readonly int totRows;

      /// <summary>
      /// Constructor with declarations of size for all arrays.
      /// </summary>
      /// <param name="totNumberOfSeats"></param>
      public SeatManager(int row, int cols)
      {
         totCols = cols;
         totRows = row;

         nameList = new string[row, cols];
         priceList = new double[row, cols];
         seatList = new string[row, cols];

         for (int rows = 0; rows < row; rows++)
         {
            for (int col = 0; col < totCols; col++)
            {
                seatList[rows, col] = "Vacant";
            }
         }
      }
   }
}


/// <summary>
/// Check if index is within bounds of the array
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
private bool CheckIndex(int index)
{
   if (index >= 0 && index < nameList.Length)
      return true;
   else
      return false;
}

/// <summary>
/// Return total number of seats
/// </summary>
/// <returns></returns>
public int GetNumOfSeats()
{
   int count = 0;

   for (int rows = 0; rows < totRows; rows++)
   {
      for (int cols = 0; cols < totCols; cols++)
      {
         count++;
      }   
   }
   return count;
}

/// <summary>
/// Calculate and return total number of reserved seats
/// </summary>
/// <returns></returns>
public int GetNumOfReserved()
{
   int totReservedSeats = 0;

   for (int rows = 0; rows < totRows; rows++)
   {
      for (int col = 0; col < totCols; col++)
      {
         if (!string.IsNullOrEmpty(nameList[rows, col]))
         {
            totReservedSeats++;
         }
      }
   }
   return totReservedSeats;
}

/// <summary>
/// Calculate and return total number of vacant seats
/// </summary>
/// <returns></returns>
public int GetNumOfVacant()
{
   int totVacantSeats = 0;

   for (int rows = 0; rows < totRows; rows++)
   {
      for (int col = 0; col < totCols; col++)
      {
         if (string.IsNullOrEmpty(nameList[rows, col]))
         {
            totVacantSeats++;
         }
      }
   }
   return totVacantSeats;
}

/// <summary>
/// Return formated string with info about the seat, name, price and its status
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public string GetSeatInfoAt(int index)
{
   int cols = ReturnColumn(index);
   int rows = ReturnRow(index);
   string strOut = string.Format("{0,2} {1,10} {2,17} {3,20} {4,35:f2}",
      rows+1, cols+1, seatList[rows, cols], nameList[rows, cols], priceList[rows, cols]);
   return strOut;
}

/// <summary>
/// Send an array containing all seats in the cinema
/// </summary>
/// <returns></returns>
public string[] GetSeatInfoString()
{
   int count = totRows * totCols;

   if (count <= 0)
      return null;

   string[] strSeatInfoStrings = new string[count];
   for (int i = 0; i < totRows * totCols; i++)
   {
      strSeatInfoStrings[i] = GetSeatInfoAt(i);
   }
   return strSeatInfoStrings;
}

/// <summary>
/// Reserve seat if seat is vacant
/// </summary>
/// <param name="name"></param>
/// <param name="price"></param>
/// <param name="index"></param>
/// <returns></returns>
public bool ReserveSeat(string name, double price, int index)
{
   int cols = ReturnColumn(index);
   int rows = ReturnRow(index);
   if (string.IsNullOrEmpty(nameList[rows, cols]))
   {
      nameList[rows, cols] = name;
      priceList[rows, cols] = price;
      seatList[rows, cols] = "Reserved";
      return true;
   }
   else
      return false;
}

public string[] ReturnVacantSeats()
{
   int totVacantSeats = int.Parse(GetNumOfVacant().ToString());
   string[] vacantSeats = new string[totVacantSeats];
   for (int i = 0; i < vacantSeats.Length; i++)
   {
      if (GetSeatInfoAt(i) == "Vacant")
      {
         vacantSeats[i] = GetSeatInfoAt(i);
      }
   }
   return vacantSeats;
}

public string[] ReturnReservedSeats()
{
   int totReservedSeats = int.Parse(GetNumOfReserved().ToString());

   string[] reservedSeats = new string[totReservedSeats];
   for (int i = 0; i < reservedSeats.Length; i++)
   {
      if (GetSeatInfoAt(i) == "Reserved")
      {
         reservedSeats[i] = GetSeatInfoAt(i);
      }
   }
   return reservedSeats;
}

/// <summary>
/// Cancel seat if seat is reserved
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public bool CancelSeat(int index)
{
   int cols = ReturnColumn(index);
   int rows = ReturnRow(index);

   if (!string.IsNullOrEmpty(nameList[rows, cols]))
   {
      nameList[rows, cols] = "";
      priceList[rows, cols] = 0.0;
      seatList[rows, cols] = "Vacant";
      return true;
   }
   else
   {
      return false;
   }
}

/// <summary>
/// Convert index to row and return value
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public int ReturnRow(int index)
{
   int vectorRow = index;
   int row;
   row = (int)Math.Ceiling((double)(vectorRow / totCols));
   return row;
}

/// <summary>
/// Convert index to column and return value
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public int ReturnColumn(int index)
{
   int row = index;
   int col = row % totCols;
   return col;
}

In MainForm, this is where I get ArgumentNullException:

lbSeats.Items.AddRange(seatMngr.ReturnVacantSeats());

And this is the method where the array is to be returned containing all vacant seats:

public string[] ReturnVacantSeats()
{
   int totVacantSeats = int.Parse(GetNumOfVacant().ToString());
   string[] vacantSeats = new string[totVacantSeats];
   for (int i = 0; i < vacantSeats.Length; i++)
   {
      if (GetSeatInfoAt(i) == "Vacant")
      {
         vacantSeats[i] = GetSeatInfoAt(i);
      }
   }
   return vacantSeats;
}

Answer

jim tollan picture jim tollan · Oct 31, 2013

wooolie,

The comments are indicating that you have the null problem due to the if statement, therefore, you need to avoid adding values that contain null to your addrange call. Option #1 would be to change lbSeats.Items.AddRange(seatMngr.ReturnVacantSeats());.

Here, you could add a `Where' clause along the lines of (untested code):

lbSeats.Items.AddRange(seatMngr.ReturnVacantSeats()
    .Where(x => !string.IsNullOrEmpty(x)));

If you prefer not to do that, you can set the initial array up with default empty string values (this will prevent null exceptions).

option #2 (change):

string[] vacantSeats = new string[totVacantSeats];

to:

string[] vacantSeats = Enumerable.Repeat(string.Empty,totVacantSeats).ToArray(); 

messy frig, might work, might be total b@llocks, but might get you past the error for now.

The alternative of course (in current code) would be option #3:

if (GetSeatInfoAt(i) == "Vacant")
{
    vacantSeats[i] = GetSeatInfoAt(i);
} else {
    vacantSeats[i] = string.empty;
}

phew...