CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 3 of 3
  1. #1
    Join Date
    Apr 2013
    Posts
    11

    [RESOLVED] IndexOutOfRangeException after making class indepedant

    Hello, I'm a rook when it comes to programming. Recently, I made this little things as a school project. I later read that the SeatManager class must be indepedant and changed my code accordingly. However, after going through all the errors, I'm getting an exception. The two relevant classes look like this:

    Code:
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace Assignment_3
    {
    	/// <summary>
    	/// This class performs all the operations for the GUI and calls the static methods used in InputUtility.
    	/// It also initializes the GUI and updates it when new info is put in.
    	/// </summary>
    	public partial class MainForm : Form
    	{
    		private const int totalNumOfSeats = 60;
    		private const int m_totNumOfCols = 10;
    		private const int m_totNumOfRows = 6;
    		
    		SeatManager m_seatMngr = new SeatManager(m_totNumOfRows, m_totNumOfCols);
    		
    		/// <summary>
    		/// Basic start-up method.
    		/// </summary>
    		public MainForm()
    		{
    			m_seatMngr.InitArrays();
    			InitializeComponent();
    			InitializeGUI();
    		}
    		
    			/// <summary>
    			/// Inserts information into the list box, disables unnecessary fields, holds the formatting for
    			/// the list box, shows how many seats are taken, vacant and there are in total and clears the fields
    			/// when they've been used.
    			/// </summary>
    		public void UpdateGUI() 
    		{	
    			if (reserveRadio.Checked) //If reservation is used, put a marker in the name field.
    			{
    				nameField.Focus();
    				nameField.Clear(); 
    				priceField.Clear();
    			}
    		}
    			/// <summary>
    			/// Makes sure the reserve radio button is checked at start-up, the list box is empty and the
    			/// name field is clear.
    			/// </summary>
    		private void InitializeGUI()
    		{
    			reserveRadio.Checked = true; //Reservation is automatically checked at start-up.
    			reservationsBox.Items.Clear(); //Nothing is in the reservations box at start-up.
    			nameField.Text = string.Empty; //Clears the field for names at start-up.
    			
    			showCombo.Items.AddRange(Enum.GetNames(typeof(DisplayOptions))); //Fills the showBox with the enums.
    			showCombo.SelectedIndex = (int)DisplayOptions.AllSeats; //Makes sure AllSeats is the selected option upon start-up.
    			
    			//Initiates labels so they don't display code until they're given an input.
    			//Why is this assigned here and in UpdateGUI? I couldn't get them to display properly otherwise.
    			totalSeatsLabel.Text = totalNumOfSeats.ToString(); 
    			int numOfVacantSeats = m_seatMngr.CountSeats();
    			reservedSeatsLabel.Text = (totalNumOfSeats - numOfVacantSeats).ToString(); //Shows number of reserved seats
    			vacantSeatsLabel.Text = numOfVacantSeats.ToString(); //Shows number of vacant seats
    			reservationsBox.SelectedIndex = 0;
    		}
    			/// <summary>
    			/// Executes when the user clicks on the OK button. Starts the validation of the input name and price
    			/// and also calls the UpdateGUI method above.
    			/// </summary>
    			/// 
    		private void OkBtnClick(object sender, EventArgs e)
    		{
    			int index = reservationsBox.SelectedIndex;
    			string name = nameField.Text;
    			string priceString = priceField.Text;
    			
    			UpdateGUI();
    			
    			if (reserveRadio.Checked)
    			{
    				ReserveOneSeat(name, priceString, index);
    			}
    			
    			else
    			{
    				CancelOneSeat(index);
    			}
    		}
    			/// <summary>
    			/// Recieves a string for a name, a string for a price and a double for a price and sends them to the
    			/// appropriate methods to be validated. If both name and price are validated, returns true.
    			/// </summary>
    		private bool ReadAndValidateInput(string name, string priceString) //Makes sure both name and price is okay.
    		{
    			double price = 0;
    			bool nameOK = ReadAndValidateName(name);
    			bool priceOK = ReadAndValidatePrice(priceString, price);
    			return nameOK && priceOK;
    		}
    			/// <summary>
    			/// Validates a name by making sure the field isn't empty or has unnecessary white spaces. Returns
    			/// true if the validation is successful. 
    			/// </summary>
    		private bool ReadAndValidateName(string name)
    		{
    			if (InputUtility.ValidateString(name))//Makes sure the name field isn't empty.
    			{				
    				return true; 
    			}
    			
    			else //Informs the user of his shortcoming and puts focus on the errenous name.
    			{
    				MessageBox.Show("Invalid name! It cannot be empty" + Environment.NewLine +
    				               "and it must have at least one character!", "Error!", MessageBoxButtons.OK);
    				nameField.Focus();
    				nameField.SelectAll();
    				return false;
    			}
    		}
    			/// <summary>
    			/// Validates a price by making sure it's positive and that it can be converted from a string to 
    			/// a double and returns true if that validation is successful.
    			/// </summary>
    		private bool ReadAndValidatePrice(string priceString, double price) //Makes sure the number is positive.
    		{		
    			if (InputUtility.GetDouble(priceString, out price))
    			{	
    				return true;
    			}
    			
    			else 
    			{
    				MessageBox.Show("Failed to input price!" + Environment.NewLine + //Display friendly message informing the user that he's doing it wrong.
    				                "Make sure you use a ',' for decimals" + Environment.NewLine +
    				                "and a positive price!", "Error!", MessageBoxButtons.OK);
    				return false;
    			}
    		}
    			/// <summary>
    			/// If the reservation radio button is checked, will enable the price and name fields.
    			/// </summary>
    		private void ReserveRadioCheckedChanged(object sender, EventArgs e) //Disables the name field and price field if cancel is checked.
    		{
    			nameField.Enabled = true;
    			priceField.Enabled = true;
    		}
    		/// <summary>
    		/// If the cancellation radio button is checked, will disable the price and name fields.
    		/// </summary>
    		private void CancelReserveRadioCheckedChanged(object sender, EventArgs e)
    		{
    			nameField.Enabled = false;
    			priceField.Enabled = false;
    		}
    		
    		/// <summary>
    		/// Contains the different steps for reserving or cancelling a seat. 
    		/// If reservation is selected, it checks the array's element to see if
    		/// it's used. If it is, it prompts the user, asking him if he wants to
    		/// continue. If it's not used, it simply calls the necessary methods
    		/// in order to write the element.
    		/// </summary>
    		/// <param name="name">The name written in the name field.</param>
    		/// <param name="priceString">The price written in the price field.</param>
    		private void ReserveOneSeat(string name, string priceString, int index)
    		{	
    			
    			if ((!m_seatMngr.IsArrayEmpty(index) == true) && (reserveRadio.Checked))
    			{
    				DialogResult seatContinue = MessageBox.Show("Seat is already taken, continue anyway?", "Seat taken", MessageBoxButtons.YesNo);
    				
    				if (seatContinue == DialogResult.Yes)
    				{
    					if (ReadAndValidateInput(name, priceString))
    					{	
    						m_seatMngr.ReserveSeat(name, priceString, index);
    						reservationsBox.Items.Clear();
    						reservationsBox.Items.AddRange(m_seatMngr.SeatsAll());
    					}		
    				}
    			}
    			
    			else if (m_seatMngr.IsArrayEmpty(index) && reserveRadio.Checked) 
    			{
    				if (ReadAndValidateInput(name, priceString)) 
    				{
    					m_seatMngr.ReserveSeat(name, priceString, index);
    					reservationsBox.Items.Clear();
    					reservationsBox.Items.AddRange(m_seatMngr.SeatsAll());
    				}
    			}
    			
    			//For the seat counter.
    			int numOfVacantSeats = m_seatMngr.CountSeats();		
    			reservedSeatsLabel.Text = (totalNumOfSeats - numOfVacantSeats).ToString(); //Shows number of reserved seats
    			vacantSeatsLabel.Text = numOfVacantSeats.ToString(); //Shows number of vacant seats
    		}
    		
    		private void CancelOneSeat(int index)
    		{		
    			if (cancelReserveRadio.Checked)
    			{
    				m_seatMngr.CancelSeat(index);
    				reservationsBox.Items.Clear();
    				reservationsBox.Items.AddRange(m_seatMngr.SeatsAll());
    			}
    			
    			else
    			{
    				MessageBox.Show("You must select a reservation!");
    			}
    
    			//For the seat counter.
    			int numOfVacantSeats = m_seatMngr.CountSeats();		
    			reservedSeatsLabel.Text = (totalNumOfSeats - numOfVacantSeats).ToString(); //Shows number of reserved seats
    			vacantSeatsLabel.Text = numOfVacantSeats.ToString(); //Shows number of vacant seats			
    		}
    
    		/// <summary>
    		/// Displays the selected attribute of seats; all, vacant-only or reserved-only.
    		/// </summary>
    		/// <param name="sender"></param>
    		/// <param name="e"></param>
    		void ShowComboSelectedIndexChanged(object sender, EventArgs e)
    		{
    			if (showCombo.SelectedIndex == 0 && reserveRadio.Checked) //All seats visible.
    			{
    				reservationsBox.Items.Clear();
    				reservationsBox.Items.AddRange(m_seatMngr.SeatsAll());
    				nameField.Enabled = true;
    				priceField.Enabled = true;
    			}
    			
    			else if (showCombo.SelectedIndex == 1) //Vacant seats visible.
    			{
    				reservationsBox.Items.Clear();
    				reservationsBox.Items.AddRange(m_seatMngr.SeatsVacant());
    				nameField.Enabled = false;
    				priceField.Enabled = false;
    			}
    			
    			else if (showCombo.SelectedIndex == 2) //Reserved seats visible.
    			{
    				reservationsBox.Items.Clear();
    				reservationsBox.Items.AddRange(m_seatMngr.SeatsReserved());
    				nameField.Enabled = false;
    				priceField.Enabled = false;
    			}
    			
    			if (showCombo.SelectedIndex == 0) 
    				okBtn.Enabled = true;
    			
    			else
    				okBtn.Enabled = false;
    		}
    	}
    }
    Code:
    using System;
    
    namespace Assignment_3
    {
    	/// <summary>
    	/// Handles the information used in MainForm.
    	/// </summary>
    	public class SeatManager
    	{	
    		static int m_totNumOfRows;
    		static int m_totNumOfCols;
    		int m_totNumOfSeats = (m_totNumOfRows * m_totNumOfCols);
    		string[,] m_nameMatrix = new string[m_totNumOfRows,m_totNumOfCols];
    		string[,] m_priceMatrix = new string[m_totNumOfRows,m_totNumOfCols];
    		string[,] seatMatrix = new string[m_totNumOfRows,m_totNumOfCols];		
    		
    		/// <summary>
    		/// Constructor that transfers parameters from another class. Also
    		/// </summary>
    		/// <param name="totalRows">Total number of rows</param>
    		/// <param name="totalCols">Total number of columns</param>
    		public SeatManager(int totalRows, int totalCols)
    		{
    			m_totNumOfCols = totalCols;
    			m_totNumOfRows = totalRows; 
    		}
    		
    		/// <summary>
    		/// Converts a single-dimension index into the row of a two-dimensional matrix.
    		/// </summary>
    		/// <param name="index">Selected index</param>
    		/// <returns>The row of the two-dimensional matrix</returns>
    		public int GetRow(int index)
    		{
    			int vectorRow = index;
    			int row;
    			row = (int)Math.Ceiling((double)(vectorRow / m_totNumOfCols));
    			return row;
    		}
    		/// <summary>
    		/// Same as above, but turns the index into the column of the two-dimensional matrix.
    		/// </summary>
    		/// <param name="index">Selected index</param>
    		/// <returns>The column of the two-dimensional matrix</returns>
    		public int GetCol(int index)
    		{
    			int row = index;
    			int col = row % m_totNumOfCols;
    			return col;
    		}
    		/// <summary>
    		/// Creates an array and fills it with information based on the matrix, but it only takes vacant slots.
    		/// </summary>
    		/// <returns>An array with vacant seats.</returns>
    		public string[] SeatsVacant()
    		{
    			int row, col;
    			int count = 0;
    			string[] vacantSeats = new string[m_totNumOfSeats]; //I do realize this way is essentially like taking your car to ride across your lawn
    																//but I did try using an instance array and then simply refilling it based on what
    			for (row = 0; row < m_totNumOfRows; row++)			//method was executed, but it didn't work. This, on the other hand, does.
    			{
    				for (col = 0; col < m_totNumOfCols; col++) 
    				{
    					if ((m_nameMatrix[row, col] == null))
    					{
    						vacantSeats[count++] = seatMatrix[row,col];
    					}
    						
    					else
    					{
    						continue;
    					}
    				}
    			}
    			
    			return vacantSeats;
    		}
    		/// <summary>
    		/// Like the method above, it creates an array and fills it with seats based on the matrix, but this one fills it with reserved seats instead.
    		/// </summary>
    		/// <returns>An array with all reserved seats.</returns>
    		public string[] SeatsReserved()
    		{
    			int row, col;
    			int count = 0;
    			string[] reservedSeats = new string[m_totNumOfSeats];
    			
    			for (row = 0; row < m_totNumOfRows; row++)
    			{
    				for (col = 0; col < m_totNumOfCols; col++) 
    				{
    					if (m_nameMatrix[row, col] != null)
    					{
    						reservedSeats[count++] = seatMatrix[row,col];
    					}
    						
    					else
    					{
    						continue;
    					}
    				}
    			}
    			
    			return reservedSeats;
    		}
    		
    		/// <summary>
    		/// Like the two previous methods, it fills an array based on the matrix, but this includes all seats.
    		/// </summary>
    		/// <returns>A one-dimensional array with all seats.</returns>
    		public string[] SeatsAll()
    		{
    			int row, col;
    			int count = 0;
    			string[] allSeats = new string[m_totNumOfSeats];
    			
    			for (row = 0; row < m_totNumOfRows; row++)
    			{
    				for (col = 0; col < m_totNumOfCols; col++) 
    				{
    					allSeats[count++] = seatMatrix[row,col];
    				}
    			}
    			
    			return allSeats;
    		}
    		
    		/// <summary>
    		/// Count the amount of seats that are vacant, for the seat counter.
    		/// </summary>
    		/// <returns>Amount of vacant seats.</returns>
    		public int CountSeats()
    		{
    			int seatCount = 0;
    			for (int row = 0; row < m_totNumOfRows; row++)
    			{
    				for (int col = 0; col < m_totNumOfCols; col++) 
    				{
    					if (seatMatrix[row,col].Contains("Vacant"))
    					    {
    							seatCount++;
    						}
    					else
    						continue;
    				}
    			}
    			
    			return seatCount;
    		}
    		
    		/// <summary>
    		/// Finds out if the selected position in the matrix has had a name assigned to it.
    		/// </summary>
    		/// <param name="index">Selected index</param>
    		/// <returns>True or false</returns>
    		public bool IsArrayEmpty(int index)
    		{
    			int row = GetRow(index);
    			int col = GetCol(index);
    			if (string.IsNullOrEmpty(seatMatrix[row,col]))
    				return true;
    			else 
    				return false;					
    		}
    		
    		/// <summary>
    		/// Reserves a seat by changing a string to the info needed for display.
    		/// </summary>
    		/// <param name="name">Name of the occupant</param>
    		/// <param name="priceString">Payment of the occupant</param>
    		/// <param name="index">The one-dimensional index used for reserving.</param>
    		public void ReserveSeat(string name, string priceString, int index)
    		{
    			int row = GetRow(index);
    			int col = GetCol(index);
    			string reserveString;
    
    			m_nameMatrix[row, col] = name;
    			m_priceMatrix[row, col] = priceString;
    			reserveString = " " + row + "   " + col + "   Occupied by" + " " + m_nameMatrix[row, col] + "	 " + m_priceMatrix[row,col] + "kr";
    			seatMatrix[row, col] = reserveString;
    		}
    		
    		/// <summary>
    		/// Cancels a seat by reverting it back to 'Vacant.'
    		/// </summary>
    		/// <param name="index">The index used to cancel</param>
    		public void CancelSeat(int index)
    		{
    			int row = GetRow(index);
    			int col = GetCol(index);
    			string cancelString;
    			
    			m_nameMatrix[row,col] = "";
    			m_priceMatrix[row, col] = "";
    			
    			cancelString = " " + row + "   " + col + "   Vacant";
    			seatMatrix[row, col] = cancelString;
    		}
    		
    		/// <summary>
    		/// Fills the matrix with 'Vacant' strings.
    		/// </summary>
    		public void InitArrays()
    		{		
    			System.Diagnostics.Debug.WriteLine(m_totNumOfRows);
    			System.Diagnostics.Debug.WriteLine(m_totNumOfCols);
    			System.Diagnostics.Debug.WriteLine(m_totNumOfSeats);
    			for (int row = 0; row < m_totNumOfRows; row++)
    			{
    				for (int col = 0; col < m_totNumOfCols; col++)
    				{
    					seatMatrix[row,col] = " " + row + "   " + col + "   Vacant";
    				}	
    			}						
    		}
    	}
    }
    It's the arrays that make the exception, any of them that use the m_totNums. But! If I got to these lines:

    Code:
    		static int m_totNumOfRows;
    		static int m_totNumOfCols;
    And change them to this:

    Code:
    		static int m_totNumOfRows = 6;
    		static int m_totNumOfCols = 10;
    The code suddenly compiles without exceptions and it's all dandy, but the SeatManager class is no longer indepedant in that regard.

    Why does this happen? I think it has something to do with the load order, that InitArrays is called before m_totNums are assigned to. How do I fix this? I have no idea.

    Help would be very much appreciated!

  2. #2
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: IndexOutOfRangeException after making class indepedant

    In the SeatManager class, the total row/col fields should not be declared as static.

    Also, move the following assignment lines inside the class constructor. You want to declare them inside the class as fields, but assign them inside the constructor.

    Code:
    int m_totNumOfSeats = (m_totNumOfRows * m_totNumOfCols);
    		string[,] m_nameMatrix = new string[m_totNumOfRows,m_totNumOfCols];
    		string[,] m_priceMatrix = new string[m_totNumOfRows,m_totNumOfCols];
    		string[,] seatMatrix = new string[m_totNumOfRows,m_totNumOfCols];

  3. #3
    Join Date
    Apr 2013
    Posts
    11

    Re: IndexOutOfRangeException after making class indepedant

    I changed it to look like this:

    Code:
    	public class SeatManager
    	{	
    		private int m_totNumOfRows;
    		private int m_totNumOfCols;
    		private int m_totNumOfSeats;
    		private string[,] m_nameMatrix;
    		private string[,] m_priceMatrix;
    		private string[,] seatMatrix;
    				
    		/// <summary>
    		/// Constructor that transfers parameters from another class.
    		/// </summary>
    		/// <param name="totalRows">Total number of rows</param>
    		/// <param name="totalCols">Total number of columns</param>
    		public SeatManager(int totalRows, int totalCols)
    		{
    			m_totNumOfCols = totalCols;
    			m_totNumOfRows = totalRows;
    			m_totNumOfSeats = (m_totNumOfRows * m_totNumOfCols);
    			
    			m_nameMatrix = new string[m_totNumOfRows,m_totNumOfCols];
    			m_priceMatrix = new string[m_totNumOfRows,m_totNumOfCols];
    			seatMatrix = new string[m_totNumOfRows,m_totNumOfCols];				
    		}
    And now it works perfectly. Thanks a boatload, Arjay!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured