I'm trying to figure out how to populate an array with an object with multiple variables. What I need is to create an array, not a list(I'm trying to learn arrays), and populate it with 5 different bourbons. Is it possible to populate the array and store the name, age, distillery in just one index? For example,
If I called index 0, it would display:
Name: Black Maple Hill
Distillery: CVI Brands, Inc
Age: 8 years
I have this so far, in which bourbon is a derived class from whiskey and call a method in the main class to prompt user for entry.
class Bourbon : Whiskey
{
private Bourbon[] bBottles = new Bourbon[5];
public void bourbon(string name, string distillery, int age)
{
Name = name;
Distillery = distillery;
Age = age;
}
public void PopulateBottles()
{
Console.WriteLine("Please enter the information for 5 bourbons:");
for (int runs = 0; runs < 5; runs ++)
{
}
}
}
In your code you haven't defined the value variable that you are using inside the for loop. You could create new instances of the class and then store them inside the array:
public void PopulateBottles()
{
Console.WriteLine("Please enter the information for 5 bourbons:");
for (int runs = 0; runs < 5; runs ++)
{
Console.WriteLine("Name:");
var name = Console.ReadLine();
Console.WriteLine("Distillery:");
var distillery = Console.ReadLine();
Console.WriteLine("Age:");
var age = int.Parse(Console.ReadLine());
var bourbon = new Bourbon(name, distillery, age);
bBottles[runs] = bourbon;
}
}
Also make sure you have defined the Bourbon class constructor properly:
public Bourbon(string name, string distillery, int age)
{
Name = name;
Distillery = distillery;
Age = age;
}
#Jonathan. Yes, it is possible, based on my interpretation. You can try making use of indexers.
Class Bourbon : Whiskey {
public Bourbon this[int index]
{
get {
return bBottles[index];
}
set {
bBottles[index] = value;
}
}
}
Check this Need to Create Property and One Constructor to achieve your requirement.
class Bourbon
{
private Bourbon[] bBottles = new Bourbon[5];
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private string distillery;
public string Distillery
{
get { return distillery; }
set { distillery = value; }
}
private int age;
public int Age
{
get { return age; }
set { age = value; }
}
public Bourbon(string name, string distillery, int age)
{
Name = name;
Distillery = distillery;
Age = age;
}
public void PopulateBottles()
{
Console.WriteLine("Please enter the information for 5 bourbons:");
for (int runs = 0; runs < 5; runs++)
{
Console.WriteLine("Name:");
var name = Console.ReadLine();
Console.WriteLine("Distillery:");
var distillery = Console.ReadLine();
Console.WriteLine("Age:");
var age = int.Parse(Console.ReadLine());
var bourbon = new Bourbon(name, distillery, age);
bBottles[runs] = bourbon;
}
}
}
Related
This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 1 year ago.
Hi I'm doing something in C# and I've ran into an index out of range error and I don't get why. I have a list with objects that hold a string. User gets to add a number of string values and thus filling the list with that same number of objects. When I later try to access the list elements using a for loop it gives me the index out of range error! This is a parody of my code that basically sums it up:
class game
{
public List<Player> PlayerList = new List<Player>();
public List<Player> Playerlist
{
get { return PlayerList; }
}
public static int PlayerCount = 0;
public void PlayGame()
{
Console.WriteLine("ENTER NUMBER OF PLAYERS: ");
PlayerCount = int.Parse(Console.ReadLine());
for (int n = 1; n < PlayerCount + 1; n++)
{
Console.WriteLine("ENTER NAME FOR PLAYER " + n + ":");
PlayerList.Add(new Player() { PlayerName = Console.ReadLine() });
}
Player playeraccess = new Player();
playeraccess.AddTurns();
}
public class Player
{
private static int throw1;
public int Throw1
{
get { return throw1; }
set { throw1 = value; }
}
private static int throw2;
public int Throw2
{
get { return throw2; }
set { throw2 = value; }
}
private static int throw3;
public int Throw3
{
get { return throw3; }
set { throw3 = value; }
}
int firstruncheck = 0;
int turnloop = 0;
int turncounter = 0;
List<Turns> playerturn = new List<Turns>();
public Player(string playername = "")
{
PlayerName = playername;
}
public string PlayerName { get; set; }
public override string ToString()
{
return base.ToString();
}
public void AddTurns()
{
game gameaccess = new game();
for(turnloop = 0; turnloop < game.PlayerCount; turnloop++)
{
gameaccess.Playerlist[turnloop].playerturn.Add(new Turns());
On This last line I get an index out of range error. But it shouldn't happen since User has added elements into PlayerList, right?
You are creating a new player list with every instance of game but keeping track of the count in a static variable (one instance of the count for all instances of the game).
To fix this you should decide whether you are keeping track of players per game (non-static list and count) or per run of your program (static list and count). For the latter, read up on static constructors.
I'm trying to return multiple parameters, if that's how to word it. I'm trying to "translate" Python code into C#.
I'm actually not quite sure what exact term I'm searching for, but I know how to do it in Python so I'll just show my code.
class Staff
{
public String name;
public int age;
/* Now in Python, you can easily write this following, but I have no
idea how this works in C#. I basically want to return all the values
for each employee in the "Staff" class */
def desc(self):
desc_str = "%s is %s years old." % (self.name, self.age)
return desc_str
}
class Program
{
public static void Main()
{
Staff Jack = new Staff();
Jack.name = "Jack";
Jack.age = 40;
Staff Jill = new Staff();
Jill.name = "Jill";
Jill.age = 50;
Console.WriteLine(Jack.desc());
Console.WriteLine(Jill.desc());
Console.ReadKey();
}
}
EDIT: I figured out that what I was searching for was get, set and ToString() and will look into it now.
The code I've translated looks like the following now:
class Staff
{
private string name;
private int age;
private string yearsold = " years old.";
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}
public string YearsOld
{
get
{
return yearsold;
}
set
{
yearsold = value;
}
}
public override string ToString()
{
return "Employee " + Name + " is " + Age + YearsOld;
}
}
class TestPerson
{
static void Main()
{
// Create a new Person object:
Staff person = new Staff();
person.Name = "Jack";
person.Age = 40;
Console.WriteLine(person);
person.Name = "Jill";
person.Age = 50;
Console.WriteLine(person);
Console.ReadKey();
}
}
Since you have a class, you can override the ToString function and use the string.Format function like so:
class Staff
{
public string name;
public int age;
public Staff(string _name, int _age)
{
this.name = _name;
this.age = _age;
}
public override string ToString()
{
return string.Format("{0} is {1} years old.", this.name, this.age);
}
}
Then to print:
Staff Jack = new Staff("Jack", 40);
Console.WriteLine(Jack); // implicitly calls Jack.ToString()
Hope that helps.
so far my code does the following.
Ask user for a numeric amount for 'players'
Then asks for names for each of the players which is added to a list and class
I'd like to call those names from the list or class (not really sure how class works) and assign it to a new string. Here's what I got so far:
public class NameVariable
{
public int ID { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
bool IsUserWrong = false;
Console.WriteLine("Write amount of players");
while (!IsUserWrong)
{
int TotalPlayers;
while (!Int32.TryParse(Console.ReadLine(), out TotalPlayers))
{
Console.WriteLine("Value must be numeric.");
}
if (TotalPlayers >= 12 && TotalPlayers <= 16)
{
List<NameVariable> PlayerList = new List<NameVariable>();
for (int index = 0; index < TotalPlayers; index++)
{
Console.WriteLine("Enter player {0}'s name:", index + 1);
PlayerList.Add(new NameVariable
{
Name = Console.ReadLine(),
ID = index
});
}
// string player1 = ???
// string player2 = ???
// and so on for 12-16 players
}
else
{
Console.WriteLine("Please enter a value between 12 and 16.");
}
}
}
}
I know that a foreach loop can be used to display all of the variables in the NameVariable class. Would just like to know how to assign each variable to a different string.
Before using the class I just used the list which worked by using
string player1 = PlayerList[0];
string player2 = PlayerList[1];
// and so on for the remaining players
Thanks in advance!
it's just
string player1 = PlayerList[0].Name;
string player2 = PlayerList[1].Name;
...
Essentially your list contains NameVariable objects. PlayerList[index] gives you the object, and .Name gives you the property value of the object.
If you want a specific player name by a specific ID number, you can use LINQ (just to give you a hint)
string player = PlayerList.Where(p => p.ID == WhateverIDNumber).First().Name;
While the answer to your immediate question, i.e., how to access properties of a class object, is as others have shown, I feel like this code has a bigger problem. That is you're trying to do too much in one function, namely, Main(). So I advice to in fact try and refactor your code so that one function does one thing. Something like:
public static int GetNumberOfPlayers()
{
Console.Write("Enter number of players: ");
int totalPlayers;
while (!Int32.TryParse(Console.ReadLine(), out totalPlayers))
{
Console.WriteLine("Value must be numeric.");
}
return totalPlayers;
}
public static List<NameVariable> GetPlayerList(int num)
{
var list = new List<NameVariable>();
for (int i = 0; i < num; i++)
{
Console.WriteLine("Enter player {0}'s name:", i + 1);
list.Add(new NameVariable
{
Name = Console.ReadLine(),
ID = i
});
}
return list;
}
public static void DisplayPlayers(List<NameVariable> list)
{
foreach(var player in list)
{
Console.WriteLine("Player {0}, Name: {1}", player.ID, player.Name);
}
}
public static void CantThinkOfAGoodName()
{
while (true)
{
int totalPlayers = GetNumberOfPlayers();
if (totalPlayers > 16 || totalPlayers < 12)
{
Console.WriteLine("Please enter a value between 12 and 16.");
}
else
{
var playerList = GetPlayerList(totalPlayers);
DisplayPlayers(playerList);
break;
}
}
}
public static void Main()
{
CantThinkOfAGoodName();
Console.ReadLine();
}
Not sure if it helps but you can use an indexer to get players by name.
public NameVariable this[string name]
Let's say you create a class for the colection
public class NameColection : List<NameVariable>
{
public NameVariable this[string name]
{
get
{
return this.FirstOrDefault(n => n.Name == name);
}
}
}
Then you access players by name
var players = new NameColection()
{
new NameVariable() { ID = 1 , Name = "John" },
new NameVariable() { ID = 2 , Name = "Paul" },
new NameVariable() { ID = 3 , Name = "George" },
new NameVariable() { ID = 4 , Name = "Ringo" }
};
var player1 = players["John"];
As NameColection inhertits from List, you will be able to add, remove or modify items the usual way.
class Program
{
struct St_test
{
public string f_name;
public string l_name;
public int age;
public string email;
}
static void proced(int number)
{
St_test s = new St_test();
Console.WriteLine("Enter the first name :");
s.f_name = Console.ReadLine();
Console.WriteLine("Enter the last name :");
s.l_name = Console.ReadLine();
agee:
Console.WriteLine("Enter the age :");
try { s.age = int.Parse(Console.ReadLine()); }
catch { Console.WriteLine("You enterd viod age"); goto agee; }
Console.WriteLine("Enter the e_mail :");
s.email = Console.ReadLine();
}
static void Main(string[] args)
{
int num;
nume:
Console.WriteLine("enter the count of people you would like to store");
try { num = int.Parse(Console.ReadLine()); }
catch { Console.WriteLine("you enterd void number"); goto nume; }
for (int i = 0; i < num; i++)
{
proced(num);
}
I want to input many of (S) to every number (num) of people.
How to repeat the procedure (proced) and every repeat the (s) variable has new name.
If I write in the procedure (proced) the next :
string r = "s" + number;
how to convert the resulted string (r) to variable to use it instead of (s) variable for each loop
You can't (easily, anyway) access variables by name like that - but there's a much better solution, which is to create a collection of some kind - an array or a list, for example.
I would suggest:
Changing your St_test struct:
Make it a non-nested type
Give it a clearer name (e.g. Person)
Make it a class
Don't expose fields - expose properties
Potentially make it immutable, taking all the values in the constructor
Changing your proced method:
Make it return a new Person
Change the name to follow .NET naming conventions
Stop using goto
Factor out the "request an integer from the user" into a method
Changing your Main method:
Create a List<Person>
Repeatedly call what used to be called proced. but add the return value into the list
You'll end up with code something like this - but don't blindly copy it. Make sure you understand everything that's happening here.
using System;
using System.Collections.Generic;
public sealed class Person
{
public string FirstName { get; }
public string LastName { get; }
public int Age { get; }
public string Email { get; }
public Person(string firstName, string lastName, int age, string email)
{
// TODO: Validation
FirstName = firstName;
LastName = lastName;
Age = age;
Email = email;
}
}
public class Test
{
private static Person CreatePersonFromUserInput()
{
Console.WriteLine("Enter the first name:");
string firstName = Console.ReadLine();
Console.WriteLine("Enter the last name:");
string lastName = Console.ReadLine();
Console.WriteLine("Enter the age:");
int age = RequestInt32();
Console.WriteLine("Enter the email address:");
string email = Console.ReadLine();
return new Person(firstName, lastName, age, email);
}
private static int RequestInt32()
{
string text = Console.ReadLine();
int ret;
while (!int.TryParse(text, out ret))
{
Console.WriteLine("Invalid value. Please try again.");
text = Console.ReadLine();
}
return ret;
}
private static void Main()
{
Console.WriteLine("Enter the count of people you would like to store:");
int count = RequestInt32();
List<Person> people = new List<Person>();
for (int i = 0; i < count; i++)
{
people.Add(CreatePersonFromUserInput());
}
// Just to show them...
foreach (Person person in people)
{
Console.WriteLine(
$"First: {person.FirstName}; Last: {person.LastName}; Age: {person.Age}; Email: {person.Email}");
}
}
}
I'm creating a registration app where you can enter the student name, id and gpa and it will all be stored in a collection list. The label is showing as 0 even when students are registered. Here is the relevant code. Any help is appreciated.
namespace Lab09
{
class Student
{
string name;
int id;
int intNumber;
decimal gpa;
public Student(string Name, int Id, decimal Gpa)
{
name = Name;
id = Id;
gpa = Gpa;
}
public string Name
{
set { name = value; }
get
{
return name;
}
}
public int Id
{
get
{
return id;
}
}
public decimal Gpa
{
get
{
return gpa;
}
}
public int Number
{
get
{
return intNumber;
}
}
}
}
namespace Lab09
{
public partial class Form1 : Form
{
List<Student> listofStudents;
int intCurrentStudent = 0;
public Form1()
{
InitializeComponent();
listofStudents = new List<Student>();
}
private void btnRegister_Click(object sender, EventArgs e)
{
try
{
if (Decimal.Parse(txtGPA.Text) > 0 && Decimal.Parse(txtGPA.Text) <= 4)
{
if (txtName.Text != "")
{
listofStudents.Add(new Student(txtName.Text, Int32.Parse(txtID.Text), Decimal.Parse(txtGPA.Text)));
intCurrentStudent = listofStudents.Count - 1;
txtName.Enabled = false;
txtID.Enabled = false;
txtGPA.Enabled = false;
btnRegister.Enabled = false;
if (listofStudents.Count > 1)
{
btnPrevious.Enabled = true;
}
displayNumStudents();
}
}
else
{
MessageBox.Show("You must enter a name and GPA must be above 0 and less than or equal to 4");
}
}
catch
{
MessageBox.Show("ID and GPA need to be numbers");
}
}
private void displayNumStudents()
{
int NumOfStudents = 0;
foreach (Student aStudent in listofStudents)
{
NumOfStudents += aStudent.Number;
}
lblNum.Text = NumOfStudents.ToString();
}
you have field int intNumber that your Number property is returning, but you aren't ever setting it. And then you're using that number to count your students, which doesn't make sense.
I assume you want the registered student count:
private void displayNumStudents()
{
int NumOfStudents = listOfStudents.Count();
lblNum.Text = NumOfStudents.ToString();
}
The variable intNumber;
In your student class is never assigned and only returned via the Number property in your Student class.
public int Number
{
get
{
return intNumber;
}
}
You need to update this property when a new Student is added to the collection.
You could modify your Student constructor to take in this argument and assign it there:
public Student(string Name, int Id, decimal Gpa, int studentNumber)
{
name = Name;
id = Id;
gpa = Gpa;
intNumber = studentNumber;
}
You would then have to pass this to the new Student object when you create it and then add it to the list, for example:
string name = txtName.Text;
int id = Int32.Parse(txtID.Text);
decimal gpa = decimal.Parse(txtGPA.Text);
int studentNumber = listofStudents.Count() + 1;
Student student = new Student(name, id, gpa, studentNumber);
listofStudents.Add(student);