简体   繁体   中英

Value cannot be null, ArgumentNullException

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;
}

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...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM