Fundamentals of Structures

Introduction

To store the values presented to it, a computer divides its memory in two parts. The heap is the section in which the objects from classes are stored. In previous lessons, we saw various examples of creating classes and creating objects from classes. Such objects are stored in the heap. We also saw that, to create an object and store it in the heap, we must use the new operator. To refer to an object stored in the heap, you must use its reference. This means that you don't need, nor get, the actual object. You only need its address in the computer memory.

The stack is the section of memory that stores small values such as natural numbers, symbols, or Boolean values. The actual values of such types are available, not simply their addresses. If you want, you can create a group of values of small types, called primitive data types. This is the role of a structure.

A structure, like a class, is a list of types used to describe an object. Unlike a class that is used for large and complex objects, a structure is used for small objects (this is not a strict rule but a "best practice"; therefore, use a structure for a small object and consequently, don't use a structure for large objects).

Practical LearningPractical Learning: Introducing Structures

  1. Start Microsoft Visual Studio. Create a new Console App named RoadSystemDatabase1 that uses the .NET 7.0 (Standard Term Support)
  2. On the main menu, click Project -> Add New Item...
  3. In the left list, click Code
  4. In the middle list, click Code File
  5. Set the name as Road

    A Simple Form

  6. Click Add
  7. Type the following lines:
    namespace RoadSystemDatabase1
    {
    
    }

Creating a Structure

To create a structure, you use the same formula as for a class but use the struct keyword. Here is an example that starts a structure:

struct Integer
{
}

Like a class, the creation of a structure can start with an access level, usually the public or the internal keyword. Here is an example:

public struct Integer
{
}

Practical LearningPractical Learning: Creating a Structure

Structures and Fields

Like a class, a structure can have fields. They are listed in the body of the structure. Here is an example:

struct Integer
{
    private int val;
}

Practical LearningPractical Learning: Adding a Field to a Structure

Structures and Properties

A structure, like a class, can have properties. A property is created using the exact same rules and suggestions we saw for classes. Here is an example of a property with a complete definition:

struct Integer
{
    private int val;

    public int Value
    {
        get { return val; }
        set { val = value; }
    }
}

Practical LearningPractical Learning: Creating Properties in a Structure

Structures and Methods

Like a class, a structure can have methods. A structure supports all concepts we reviewed for methods of classes. A method of a structure can be of type void. Here is an example:

struct Integer
{
    private int val;

    public int Value
    {
        get { return val; }
        set { val = value; }
    }

    public void Read()
    {
    }
}

In the same way, a method can return a value of a primitive type. A method can use one or more parameters. A method can be overloaded with various versions that take different parameters.

Practical LearningPractical Learning: Adding a Method to a Structure

Structures and Constructors

A Default Constructor

As seen with a class, a default constructor is a method that holds the same name as the class and doesn't return a value. Like a class, a structure can have a default constructor. Here is an example:

internal struct Toilet
{
    public Toilet()
    {
    }
}

One of the differences between a class and a structure is that, if a struture has one or more fields and/or properties, if you create a default constructor in a structure, you must initialize everyone of the fields in the default constructor.

Practical LearningPractical Learning: Adding a Method to a Structure

Parameterized Constructors

As seen with a class, you can create a constructor that uses one or more parameters in a structure. The constructors of a structure follow the same rules and suggestions of constructors of a class. Here is an example:

struct Integer
{
    private int val;

    public Integer(int number)
    {
        val = number;
    }
    
    public int Value
    {
        get { return val; }
        set { val = value; }
    }

    public void Read()
    {
    }
}

A constructor can be overloaded with various versions that use different parameters. Here is an example:

struct Integer
{
    private int val;

    public Integer(int number)
    {
        val = number;
    }
    
    public Integer(string number)
    {
        val = int.Parse(number);
    }
    
    public Integer(int number, int maximumSize)
    {
        val = number;
        maximumSize = 1;
    }
    
    public int Value
    {
        get { return val; }
        set { val = value; }
    }

    public void Read()
    {
    }
}

Practical LearningPractical Learning: Adding Constructors to a Structure

  1. To create two constructors, type the following code:
    namespace RoadSystemDatabase1
    {
        internal struct Road
        {
            private string? id;
            private double len;
            private string? ending;
            private string? beginning;
    
            public Road()
            {
                len       = 0.00;
                id        = default;
                ending    = default;
                beginning = default;
            }
    
            public Road(string identification)
            {
                len       = default;
                ending    = default;
                beginning = default;
                id        = identification;
            }
    
            public Road(string identification, double length)
            {
                ending    = default;
                len       = length;
                beginning = default;
                id        = identification;
            }
    
            public string? Designation
            {
                get
                {
                    return id;
                }
                set
                {
                    id = value;
                }
            }
       
            public double Distance
            {
                get { return len;  }
                set { len = value; }
            }
    
            public string? Start
            {
                get { return beginning; }
                set { beginning = value; }
            }
    
            public string? End
            {
                get { return ending; }
                set { ending = value; }
            }
    
            public double GetDistanceInKilometers()
            {
                return len * 1.6093;
            }
        }
    }
  2. Click the Program.cs tab to access the primary document of the project

Creating an Object from a Structure

To use a structure, you can declare a variable of it. Initialize the variable as done for a class, using the new operator. Remember that a structure always has a default constructor. Therefore, if you don't have an initial value, initialize the variable with the default constructor. Here is an example:

internal struct Integer
{
    private int val;

    public Integer(int number)
    {
        val = number;
    }

    public Integer(string number)
    {
        val = int.Parse(number);
    }

    public Integer(int number, int maximumSize)
    {
        val = number;
        maximumSize = 1;
    }

    public int Value
    {
        get { return val; }
        set { val = value; }
    }

    public void Read()
    {
    }
}

public class Exercise
{
    public void Create()
    {
        Integer itg = new Integer();
    }
}

You can also initialize the variable with a constructor that uses one or more parameters. Here is an example:

internal struct Integer
{
    private int val;

    public Integer(int number)
    {
        val = number;
    }
}

Integer itg = new Integer(1257);

As done for variables of the other types and as seen for classes, to declare a variable for a structure, you can use the var keyword.

Accessing the Members of a Structure

After declaring a variable of a structure, you can use the object the same way you would use a class. You can access its members (fields, properties, and methods) using the period operator. Here is an example:

internal struct Integer
{
    private int val;

    public Integer(int number)
    {
        val = number;
    }

    public int Value
    {
        get { return val; }
        set { val = value; }
    }
}

public class Exercise
{
    public void Create()
    {
        Integer itg = new Integer();

    	itg.Value = 1500;
    }
}

Practical LearningPractical Learning: Accessing a Structure

  1. Change the document as follows:
    using static System.Console;
    using RoadSystemDatabase1;
    
    Road rd = new Road();
    rd.Designation = "I-83";
    rd.Distance = 85.3;
    rd.Start = "East Fayette Street / North President Street / Fallsway in Baltimore, MD";
    rd.End = "I-81 / US 322 / Capital Beltway in Harrisburg, PA";
    
    WriteLine("Road System Database");
    WriteLine("=====================================================================================");
    WriteLine("Road Name: {0}", rd.Designation);
    WriteLine("Length:    {0}  miles, {1} kilometers", rd.Distance, rd.GetDistanceInKilometers());
    WriteLine("Start:     {0}", rd.Start);
    WriteLine("End:       {0}", rd.End);
    WriteLine("=====================================================================================");
  2. To execute the application to see the result, on the main menu, click Debug -> Start Without Debugging:
    Road System Database
    =====================================================================================
    Road Name: I-83
    Length:    85.3  miles, 137.27329 kilometers
    Start:     East Fayette Street / North President Street / Fallsway in Baltimore, MD
    End:       I-81 / US 322 / Capital Beltway in Harrisburg, PA
    =====================================================================================
    
    Press any key to close this window . . .
  3. To close the window and return to your programming environment, press Enter

Topics on Structures

Fields and Constructors

We have seen that every new structure automatically has a default constructor and you are not allowed to explicitly create a default constructor. If you do, you would receive an error.

As mentioned previously, in a structure, you can create one or more fields, as (a) local variable(s). One of the differences between a class and structure is that, if you create a field in a structure, you must initialize that field in a constructor of the structure (if you create a field in a class, you are not required to initialize that field). Here is an example:

internal struct Sit
{
    int _size;

    public Sit(int size) { this._size = size; }
}

Structures and Inheritance

A structure is sealed from inheritance. This means that you cannot create a class or a structure that is based on, or is derived from, a structure.

Structures and Enumerations

An enumeration can be involved with a structure. The typical way is to create a field that is of an enumeration type. Here is an example:

public enum Category { Highway, Interstate }

internal struct Road
{
    Category cat;
}

In the same way, you can create a property of the type of an enumeration. You can then use the property like we learned for classes.

Practical LearningPractical Learning: Using an Enumeration

  1. In the Solution Explorer, right-click RoadSystemDatabase1 -> Add -> New Item...
  2. In the left list under C# Items, click Code and, in the middle list, click Code File
  3. Change the name to Category
  4. Press Enter
  5. To create an enumeration, type the code as follows:
    namespace RoadSystemDatabase1
    {
        internal enum Category
        {
            Regular,
            StateHighway,
            USHighway,
            Interstate,
            Beltway
        }
    }
  6. On the main menu, click Window -> Road.cs
  7. Change the code as follows:
    namespace RoadSystemDatabase1
    {
        internal struct Road
        {
            Category cat;
            private string? id;
            private double len;
            private string? ending;
            private string? beginning;
    
            public Road()
            {
                len       = 0.00;
                id        = default;
                ending    = default;
                beginning = default;
                cat       = Category.Regular;
            }
    
            public Road(string identification)
            {
                len       = default;
                ending    = default;
                beginning = default;
                id        = identification;
                cat = Category.Regular;
            }
    
            public Road(string identification, double length)
            {
                ending    = default;
                len       = length;
                beginning = default;
                id        = identification;
                cat = Category.Regular;
            }
    
            public string? Designation
            {
                get
                {
                    return id;
                }
                set
                {
                    id = value;
                }
            }
    
            public Category RoadType
            {
                get { return cat;  }
                set { cat = value; }
            }
    
            public double Distance
            {
                get { return len; }
                set { len = value; }
            }
    
            public string? Start
            {
                get { return beginning; }
                set { beginning = value; }
            }
    
            public string? End
            {
                get { return ending; }
                set { ending = value; }
            }
    
            public double GetDistanceInKilometers()
            {
                return Distance * 1.6093;
            }
        }
    }
  8. Click the RoadSystemDatabase.cs tab
  9. Change the document as follows:
    using static System.Console;
    
    using RoadSystemDatabase1
    
    Road rd = new Road();
    rd.Designation = "I-83";
    
    // Roads Categories: Regular, Beltway, Interstate, US Highway, State Highway
    rd.RoadType = Category.Interstate;
    
    rd.Distance = 85.3;
    rd.End = "I-81 / US 322 / Capital Beltway in Harrisburg, PA";
    rd.Start = "East Fayette Street / North President Street / Fallsway in Baltimore, MD";
    
    WriteLine("Road System Database");
    WriteLine("=====================================================================================");
    WriteLine("Road Name: {0}", rd.Designation);
    
    WriteLine("Road Type: {0}", rd.RoadType);
    
    WriteLine("Start:     {0}", rd.Start);
    WriteLine("End:       {0}", rd.End);
    WriteLine("Length:    {0} miles, {1} kilometers", rd.Distance, rd.GetDistanceInKilometers());
    WriteLine("=====================================================================================");
  10. To execute the project, press Ctrl + F5
    Road System Database
    =====================================================================================
    Road Name: I-83
    Start:     East Fayette Street / North President Street / Fallsway in Baltimore, MD
    End:       I-81 / US 322 / Capital Beltway in Harrisburg, PA
    Road Type: Interstate
    Length:    85.3  miles, 137.27329 kilometers
    =====================================================================================
    
    Press any key to close this window . . .
  11. To close the window and return to your programming environment, press E

Expression-Bodied

We already know that the C# language provides the => operator that can be used to simplify the code of a function/method or the code of a property. This operator is used in a structure the same way it is used in a class.

Practical LearningPractical Learning: Creating Expression-Bodied Propertie and Methods

  1. Click the Road.cs tab and change the class as follows:
    namespace RoadSystemDatabase1
    {
        internal struct Road
        {
            private Category cat;
            private string?  id;
            private double   len;
            private string?  ending;
            private string?  beginning;
    
            public Road()
            {
                len       = 0.00;
                id        = default;
                ending    = default;
                beginning = default;
                cat       = Category.Regular;
            }
    
            public Road(string identification)
            {
                len       = default;
                ending    = default;
                beginning = default;
                id        = identification;
                cat       = Category.Regular;
            }
    
            public Road(string identification, double length)
            {
                ending    = default;
                len       = length;
                beginning = default;
                id        = identification;
                cat       = Category.Regular;
            }
    
            public string? Designation
            {
                get => id;
                set => id = value;
            }
    
            public Category RoadType
            {
                get => cat;
                set => cat = value;
            }
    
            public double Distance
            {
                get => len;
                set => len = value;
            }
    
            public string? Start
            {
                get => beginning;
                set => beginning = value;
            }
    
            public string? End
            {
                get => ending;
                set => ending = value;
            }
    
            public double GetDistanceInKilometers() => Distance * 1.6093;
        }
    }
  2. To execute, on the main menu, click Debug -> Start Without Debugging
  3. Close the window and return to your programming environment

Automatic Properties

The properties of a structure can be created as automatic ones. Those properties are created and follow the same rules we applied to those of classes. Here are examples:

namespace RoadSystemDatabase
{
    internal struct Road
    {
        public string? Designation { get; set; }
        public Category RoadType { get; set; }
        public double Distance{ get; set; }
        public string? Start { get; set; }
        public string? End { get; set; }

        public double GetDistanceInKilometers() => Distance * 1.6093;
    }
}

A Property of a Structure Type

Once a structure exists, you can use it as a type. For example, you can create a property that is a structure type. The rules are the same we reviewed for creating a property of a class. Here are examples:

public enum Category
{
    Regular,
    StateHighway,
    USHighway,
    Interstate,
    CapitalBeltway
}

internal struct Road
{
    private string? id;
    private double len;
    private Category cat;
    private string? ending;
    private string? beginning;

    public Road(string identification)
    {
        len = 0.00;
        ending = "";
        beginning = "";
        id = identification;
        cat = Category.Regular;
    }

    public Road(string identification, Category type, double length)
    {
        cat = type;
        ending = "";
        len = length;
        beginning = "";
        id = identification;
    }

    public string? Designation
    {
        get
	{
            return id;
        }
        set
        {
            id = value;
        }
    }

    public Category RoadType
    {
        get { return cat; }
        set { cat = value; }
    }
   
    public double Distance
    {
        get { return len;  }
        set { len = value; }
    }
    public string? Start
    {
        get { return beginning; }
        set { beginning = value; }
    }
    public string? End
    {
        get { return ending; }
        set { ending = value; }
    }

    public double GetDistanceInKilometers()
    {
        return len * 1.6093;
    }
}

public class Intersection
{
    public Road Road1 { get; set; }
    public Road Road2 { get; set; }
    public string InOrNear { get; set; }

    public Intersection()
    {
    }

    public Intersection(Road one, Road two, string position)
    {
        Road1 = one;
        Road2 = two;
        InOrNear = position;
    }
}

After creating the property, you can use it as you see fit.

Returning a Structure From a Function or Method

Like a regular data type or a class, a structure can serve as the return type of a function or a method. The rules are more related to those of a class. When creating the method, type the name of the structure on the left side of the name of the method. In the body of the method, implement the desired behavior. Before exiting the method, make sure you return a valid value that is of the type of the structure.

When a method returns a value of the type of a structure, you can assign the method call to a variable of the type of the structure.

Passing a Structural Object as Argument

Like a regular data type, a structure can be used as the type of a parameter of a method. The argument is primarily passed as done for a class. After passing the argument, in the body of the method, you can access the public members of the structure, using the period operator.

Practical LearningPractical Learning: Using a Structure Object

  1. Click the ReadSystemDatabase.cs tab and change the document as follows:
    using static System.Console;
    using RoadSystemDatabase;
    
    // Returning a structural object from a function
    Road Create()
    {
        Road rd = new Road();
    
        rd.Distance = 232.406;
        rd.Designation = "US 36";
        rd.RoadType = Category.USHighway;
        rd.End = "US-36 on CO-KS border";
        rd.Start = "Deer Ridge - US 34";
    
        return rd;
    }
    
    // Passing a structural object as argument
    void Show(object obj)
    {
        if (obj is null)
            return;
    
        Road rd = (Road)obj;
    
        WriteLine("Road System Database");
        WriteLine("============================================");
        WriteLine("Road Name: {0}", rd.Designation);
        WriteLine("Road Type: {0}", rd.RoadType);
        WriteLine("--------------------------------------------");
        WriteLine("Start:     {0}", rd.Start);
        WriteLine("End:       {0}", rd.End);
        WriteLine("Length:    {0:N} miles ({1:N} kilometers)", rd.Distance, rd.GetDistanceInKilometers());
        WriteLine("============================================");
    }
    
    Road rd = Create();
    Show(rd);
  2. To execute, on the main menu, click Debug -> Start Without Debugging:
    Road System Database
    ============================================
    Road Name: US 36
    Road Type: USHighway
    --------------------------------------------
    Start:     Deer Ridge - US 34
    End:       US-36 on CO-KS border
    Length:    232.41 miles (374.01 kilometers)
    ============================================
    
    Press any key to close this window . . .
  3. Press Z to close the window and return to your programming environment

Passing a Structural Object by Reference

When you pass a structure to a method, it is referred to as passing by value. A copy of the value of the structure is passed to the method. If the method modifies the argument, the original variable would stay intact. If you want the method to modify the value of the structure, you can pass the argument by reference. You can do this using the (rules of the) ref and the out keywords.

Practical LearningPractical Learning: Ending the Lesson


Previous Copyright © 2001-2023, FunctionX Friday 26 November 2021 Next