Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array of structs in C#

Tags:

arrays

c#

struct

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

like image 561
n1te Avatar asked Aug 13 '11 14:08

n1te


3 Answers

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.

like image 64
sll Avatar answered Sep 19 '22 08:09

sll


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.

like image 37
Nick B Avatar answered Sep 17 '22 08:09

Nick B


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.

like image 38
IAbstract Avatar answered Sep 17 '22 08:09

IAbstract