I'm trying to get input from user using array of structs and then print it:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CA4
{
class Program
{
static void Main(string[] args)
{
StudentDetails[,] student = new StudentDetails[5, 1];
Console.WriteLine("Please enter the unit code:");
student[0, 0].unitCode = Console.ReadLine();
Console.WriteLine("Please enter the unit number:");
student[1, 0].unitNumber = Console.ReadLine();
Console.WriteLine("Please enter first name:");
student[2, 0].firstName = Console.ReadLine();
Console.WriteLine("Please enter last name:");
student[3, 0].lastName = Console.ReadLine();
Console.WriteLine("Please enter student mark:");
student[4, 0].studentMark = int.Parse(Console.ReadLine());
for (int row = 0; row < 5; row++)
{
Console.WriteLine();
for (int column = 0; column < 1; column++)
Console.WriteLine("{0} ", student[row, column]);
}
Console.ReadLine();
}
public struct StudentDetails
{
public string unitCode; //eg CSC10208
public string unitNumber; //unique identifier
public string firstName; //first name
public string lastName;// last or family name
public int studentMark; //student mark
}
}
}
Unfortunately after entering all the data I get:
CA4.Program+StudentDetails
CA4.Program+StudentDetails
CA4.Program+StudentDetails
CA4.Program+StudentDetails
CA4.Program+StudentDetails
It doesn't crash, just instead of the data that I entered get the above 5 lines.
I know that the reason why it doesn't work is that I don't use the structs correctly because without them there is no problem.
Can somebody please help me and tell me how to use structs propely in the example above. Thanks
Cheers,
n1te
Your call to Console.WriteLine("{0} ", student[row, column]);
is implicitly calling the ToString() method of the StudentDetails struct, which just writes out the name of the struct type by default. Override the ToString() method:
public struct StudentDetails
{
public string unitCode; //eg CSC10208
public string unitNumber; //unique identifier
public string firstName; //first name
public string lastName;// last or family name
public int studentMark; //student mark
public override string ToString()
{
return string.Format("{0},{1},{2},{3},{4}", unitCode,
unitNumber,firstName,lastName,studentMark);
}
}
However, the larger issue is that you are setting the properties of 5 different StudentDetails structs... by declaring an array StudentDetails[,] student = new StudentDetails[5, 1];
and asking the user to input details about the structs at different points in the array, i.e. student[0, 0]
then student[1,0]
, you aren't making one StudentDetails object and setting properties on it, you created 5 different StudentDetails objects.
Why are you using an array? If you want to the user to fill in a single StudentDetails object, just do
StudentDetails student = new StudentDetails();
Console.WriteLine("Please enter the unit code:");
student.unitCode = Console.ReadLine();
Console.WriteLine("Please enter the unit number:");
student.unitNumber = Console.ReadLine();
...
Then to write it out:
Console.WriteLine("{0}", student);
This will use the ToString() method you declared in your StudentDetails struct. (ToString() is called whenever an object needs to be converted to a string, you just don't always have to write it)
Hope this helps.
This is because by default ToString()
returns a Type name, you've to override it yourself for StudentDetails
struct:
public struct StudentDetails
{
public override void ToString()
{
return String.Format(
CultureInfo.CurrentCulture,
"FirstName: {0}; LastName: {1} ... ",
this.FirstName,
this.LastName);
}
}
BTW, why you are using stuct and legacy arrays? Consider using class
instead struct
, and Generic IList<StudentDetails>
or IDictionary<int, StudentDetails>
instead of array.
Because legacy arrays together with struct (basically value type) introduces a boxing (struct -> object) each time you've adding item to array and unboxing (object -> struct) when reading it back.
Others have covered the override of ToString()
, so I won't rehash that information. More so, to your request:
Can somebody please help me and tell me how to use structs propely in the example above.
See MSDN: Structure Design
First, your struct is mutable. Immutable structs are not always the best solution but should be considered ...see a post I have on Microsoft's use of structs inside the Dictionary class. That said, I would determine the basic requirement: Does the struct require mutability? In other words, will the student's name, unit number, or mark change after struct instantiation?
Second, if the requirement is to have a collection of StudentDetails
, an array is fine:
// declare students collection
StudentDetail[] students = new StudentDetail[5];
// declare an array indexer
int indexer = 0;
static void Main(string[] args)
{
Console.WriteLine("Please enter the unit code:");
string unitCode = Console.ReadLine();
Console.WriteLine("Please enter the unit number:");
string unitNumber = Console.ReadLine();
/* get the rest of your inputs */
AddStudentDetails(unitCode, unitNumber, firstName, lastName, studentMark);
}
// demonstrate auto-magically instantiated, mutable struct
void AddStudentDetails(string unitCode, string unitNumber, string firstName, string lastName, int studentMark)
{
students[indexer].unitCode = unitCode;
students[indexer].unitNumber = unitNumber;
students[indexer].firstName = firstName;
students[indexer].lastName = lastName;
students[indexer].studentMark = studentMark;
// increment your indexer
indexer++;
}
Note: exception handling is not considered in this example; e.g., incrementing beyond the bounds of the array.
In the previous example, you could change any of the properties of the StudentDetails
struct after instantiation. Structs are made more safe when immutable:
public struct StudentDetails
{
public readonly string unitCode; //eg CSC10208
public readonly string unitNumber; //unique identifier
public readonly string firstName; //first name
public readonly string lastName;// last or family name
public readonly int studentMark; //student mark
// use a public constructor to assign the values: required by 'readonly' field modifier
public StudentDetails(string UnitCode, string UnitNumber, string FirstName, string LastName, int StudentMark)
{
this.unitCode = UnitCode;
this.unitNumber = UnitNumber;
this.firstName = FirstName;
this.lastName = LastName;
this.studentMark = StudentMark;
}
}
This requires a change in how you add the details object to the students array:
void AddStudentDetails(string unitCode, string unitNumber, string firstName, string lastName, int studentMark)
{
students[indexer] = new StudentDetails(unitCode, unitNumber, firstName, lastName, studentMark);
// increment your indexer
indexer++;
}
Consider the requirements for the struct and design appropriately.
You need to print the members of the struct appropriately. I would suggest a method that does the printing for you given a struct such as
public void PrintStruct(StudentDetails stDetails)
{
Console.WriteLine(stDetails.firstName);
Console.WriteLine(stDetails.lastName);
.... etc
}
Alternatively create a Class (This is C#) and override the ToString() method to return a string with all the member information and you won't need to modify your main code.
Structs are all right to use in C# but in cases where you need data representation rather than just simple data transfer than you should use a class.