Array of structs in C#

15,808

Solution 1

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.

Solution 2

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.

Solution 3

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.

Solution 4

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.

Share:
15,808
n1te
Author by

n1te

49206c757620636f64696e672e200d0a0d0a453a206e3174656c6565745b61745 d5b656d61696c2e73797374656d2e637265617465642e62792e676f6f676c655d

Updated on June 27, 2022

Comments

  • n1te
    n1te almost 2 years

    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

  • siride
    siride over 12 years
    Minor nitpick: string builder is a lot of work for no gain. Just use concatenation or a single string.Format().
  • n1te
    n1te over 12 years
    First of all thanks to everybody for prompt responses To be honest I dont have to use an array here but the next assignment is similar and I'm required to use arrays there, so I wanted to practice. In the next assignment I have to accept the data as: week number, home team name, away team name, win (1 or 0) _italic_Your program must use an array/s of structures to store the data in memory, i.e. your program must read the data from the file/s into memory as an array of structs and manipulate the data in the array. and there will be 5 weeks total and 80 matches (there is 16 teams)
  • n1te
    n1te over 12 years
    That's why I figured that I would give it a go here so it's easier in the next assignment. @Nick Bradley
  • Nick B
    Nick B over 12 years
    That's fine, as long as you understand that, in the original code you posted, you aren't filling in a StudentDetails struct - you are filling in five different ones, but you are only filling in the unitCode in the 1st one (At [0,0]) unitNumber in the 2nd one ([1,0]) firstName in the 3rd.. etc. You aren't completely filling any of the StudentDetails structs you make.
  • IAbstract
    IAbstract over 12 years
    "but in cases where you need data representation rather than just simple data transfer than you should use a class." ...not always true. ;)
  • IAbstract
    IAbstract over 12 years
    @n1te: keep to the requirements of your current assignment. While it shows desire to learn, not following the requirements could negatively reflect on the grade you receive. ;)
  • Olivier Jacot-Descombes
    Olivier Jacot-Descombes over 12 years
    I agree with Nick. What you probably need is a 1-dimensional array of StudenDetails. student[0].firstName = "Mickey"; student[0].lastName = "Mouse";
  • n1te
    n1te over 12 years
    Thanks a lot for the answer, it will make my life a lot easier in the next assignment. Btw. Good point with keeping the requirements, will do :)