Classes and Functions

Introduction

We have already learned how to create an object by declaring a variable of a class type. Here is an example:

using static System.Console;

Square sqr = new(248.57);
    
WriteLine("Square Characteristics");
WriteLine("----------------------------");
WriteLine("Side:      {0}", sqr.Side);
WriteLine("Perimeter: {0}", sqr.CalculatePerimeter());
WriteLine("Area:      {0}", sqr.CalculateArea());
WriteLine("============================");
    
public class Square(double side)
{
    public double Side
    {
        get { return side; }
    }
    
    public double CalculatePerimeter()
    {
        return side * 4;
    }
    
    public double CalculateArea()
    {
        return side * side;
    }
}

This would produce:

Square Characteristics
----------------------------
Side:      248.57
Perimeter: 994.28
Area:      61787.04489999999
============================
    
Press any key to close this window . . .

As mentioned in our introduction to classes, when you declare a variable using the new operator, you are said to get a reference to the memory area where the object will be located.

Practical LearningPractical Learning: Introducing Parameters

  1. Start Microsoft Visual Studio
  2. Create a new Console App named PayrollPreparation4 that supports .NET 8.0 (Long-Term Support)
  3. In the Solution Explorer, right-click PayrollPreparation4 -> Add -> New Folder
  4. Type Models as the name of the new folder
  5. In the Solution Explorer, right-click the new Models folder -> Add -> Class...
  6. Type Employee as the name of the new class/file
  7. Click Add
  8. Change the class as follows:
    namespace PayrollPreparation4.Models
    {
        internal class Employee
        {
            internal required int    EmployeeNumber { get; set; }
            internal required string FirstName      { get; set; }
            internal required string LastName       { get; set; }
            internal required double HourlySalary   { get; set; }
        }
    }
  9. In the Solution Explorer, right-click the Model folder -> Add -> Class...
  10. Type TimeSheet as the name of the new class/file
  11. Click Add
  12. Change the class as follows:
    namespace PayrollPreparation40.Models
    {
        internal class TimeSheet
        {
            private int tsNbr;
            private int empl;
            private double salary;
            private double result;
    
            private double mon, tue, wed, thu, fri;
    
            internal TimeSheet(int ts, int emplNbr, double m, double t, double w, double h, double f)
            {
                tsNbr = ts;
                empl = emplNbr;
                mon = m;
                tue = t;
                wed = w;
                thu = h;
                fri = f;
            }
    
            internal int GetTimeSheetNumber()
            {
                return tsNbr;
            }
    
            internal int GetEmployeeNumber()
            {
                return empl;
            }
    
            internal double GetMondayWork()
            {
                return mon;
            }
    
            internal double GetTuesdayWork()
            {
                return tue;
            }
    
            internal double GetWednesdayWork()
            {
                return wed;
            }
    
            internal double GetThursdayWork()
            {
                return thu;
            }
    
            internal double GetFridayWork()
            {
                return fri;
            }
    
            private double GetSalary()
            {
                salary = 0.00;
    
                if (empl == 370_595)
                {
                    salary = 28.25;
                }
                else if (empl == 826_384)
                {
                    salary = 24.37;
                }
                else if (empl == 175_004)
                {
                    salary = 26.97;
                }
                else if (empl == 697_415)
                {
                    salary = 31.57;
                }
                else
                    salary = 0.00;
    
                return salary;
            }
    
            internal double CalculateTimeWorked()
            {
                return mon + tue + wed + thu + fri;
            }
    
            internal double CalculateRegularTime(double time)
            {
                result = time;
    
                if (time is > 40.00)
                {
                    result = 40.00;
                }
    
                return result;
            }
    
            internal double CalculateRegularPay(double time)
            {
                result = GetSalary() * time;
    
                if (time is > 40.00)
                {
                    result = GetSalary() * 40.00;
                }
    
                return result;
            }
    
            internal double CalculateOvertime(double time)
            {
                result = 0.00;
    
                if (time is > 40.00)
                {
                    result = time - 40.00;
                }
    
                return result;
            }
    
            internal double CalculateOvertimePay(double time)
            {
                result = 0.00;
    
                if (time is > 40.00)
                {
                    result = salary * 1.50 * time;
                }
    
                return result;
            }
    
            internal double CalculateGrossPay(double time)
            {
                return CalculateRegularPay(time) + CalculateOvertimePay(time);
            }
        }
    }

Producing an Object

You can create a function that returns an object. To start, when creating the function, specify its return type as the desired class. In the body of the function, you can do anything you want. Before the closing curly bracket of the function, you must return an object of the class indicated as the returned type.

ApplicationPractical Learning: Producing Objects

  1. In the Solution Explorer, right-click Program and click Rename
  2. Type PayrollProcessing (to get PayrollProcessing.cs)
  3. Above the Code Editor, click the PayrollProcessing.cs tab and change the document as follows:
    using PayrollPreparation4.Models;
    using static System.Console;
    
    PreparePayroll();
    
    Employee Hire(int number)
    {
        Employee empl1 = new Employee()
        {
            EmployeeNumber = 370_595,
            FirstName      = "Michael",
            LastName       = "Carlock",
            HourlySalary   = 28.25
        };
        Employee empl2 = new Employee()
        {
            EmployeeNumber = 826_384,
            FirstName      = "Catherine",
            LastName       = "Busbey",
            HourlySalary   = 24.37
        };
        Employee empl3 = new Employee()
        {
            EmployeeNumber = 175_004,
            FirstName      = "Andrew",
            LastName       = "Sanders",
            HourlySalary   = 26.97
        };
        Employee empl4 = new Employee()
        {
            EmployeeNumber = 697_415,
            FirstName      = "Jennifer",
            LastName       = "Simms",
            HourlySalary   = 31.57
        };
    
        if (number == 370_595)
        {
            return empl1;
        }
        else if (number == 826_384)
        {
            return empl2;
        }
        else if (number == 175_004)
        {
            return empl3;
        }
        else if (number == 697_415)
        {
            return empl4;
        }
    
        return new Employee() { EmployeeNumber = 0, FirstName = "John", 
                                LastName = "Doe", HourlySalary = 0.00 };
    }
    
    TimeSheet GetTimeWorked(int number)
    {
        TimeSheet ts1 = new TimeSheet(100_000, 370_595, 7,    8,    6.5, 8.5, 6.5);
        TimeSheet ts2 = new TimeSheet(205_000, 826_384, 9.5,  8,   10.5, 9,   8.5);
        TimeSheet ts3 = new TimeSheet(505_500, 175_004, 9,   10.5,  7,   9.5, 8.5);
        TimeSheet ts4 = new TimeSheet(202_240, 697_415, 8,    8,    8,   8,   8  );
    
        if (number == 205_000)
        {
            return ts2;
        }
        else if (number == 202_240)
        {
            return ts4;
        }
        else if (number == 505_500)
        {
            return ts3;
        }
        else if (number == 100_000)
        {
            return ts1;
        }
    
        return new TimeSheet(0, 0, 0, 0, 0, 0, 0);
    }
    
    void PreparePayroll()
    {
        int nbr = 100_000;
    
        TimeSheet timeSheet = GetTimeWorked(nbr);
        Employee  staff     = Hire(timeSheet.GetEmployeeNumber());
    
        double timeWorked   = timeSheet.CalculateTimeWorked();
    
        WriteLine("+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+");
        WriteLine("FUN DEPARTMENT STORE");
        WriteLine("=======================================================");
        WriteLine("Payroll Evaluation");
        WriteLine("=======================================================");
        WriteLine("Employee Information");
        WriteLine("-------------------------------------------------------");
        WriteLine("Employee #:      {0}", timeSheet.GetEmployeeNumber());
        WriteLine($"Full Name:       {staff.FirstName} {staff.LastName}");
        WriteLine($"Hourly Salary:   {staff.HourlySalary:f}");
        WriteLine("=======================================================");
        WriteLine("Time Worked Summary");
        WriteLine("--------+---------+-----------+----------+-------------");
        WriteLine(" Monday | Tuesday | Wednesday | Thursday | Friday");
        WriteLine("--------+---------+-----------+----------+-------------");
        Write($"  {timeSheet.GetMondayWork():f}  |   ");
        Write($"{timeSheet.GetTuesdayWork():f}  |    ");
        Write($"{timeSheet.GetWednesdayWork():f}   |   ");
        Write($"{timeSheet.GetThursdayWork():f}   |  ");
        WriteLine($"{timeSheet.GetFridayWork():f}");
        WriteLine("========+=========+===========+==========+=============");
        WriteLine("                                    Pay Summary");
        WriteLine("-------------------------------------------------------");
        WriteLine("                                   Time   Pay");
        WriteLine("-------------------------------------------------------");
        WriteLine("                     Regular:    {0:f}   {1:f}",
                timeSheet.CalculateRegularTime(timeWorked),
                timeSheet.CalculateRegularPay(timeWorked));
        WriteLine("-------------------------------------------------------");
        WriteLine("                     Overtime:    {0:f}   {1:f}",
                timeSheet.CalculateOvertime(timeWorked),
                timeSheet.CalculateOvertimePay(timeWorked));
        WriteLine("=======================================================");
        WriteLine("                     Net Pay:            {0:f}",
                timeSheet.CalculateGrossPay(timeWorked));
        WriteLine("=======================================================");
    }
  4. To execute, on the main menu, click Debug -> Start Without Debugging:
    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    FUN DEPARTMENT STORE
    =======================================================
    Payroll Evaluation
    =======================================================
    Employee Information
    -------------------------------------------------------
    Employee #:      370595
    Full Name:       Michael Carlock
    Hourly Salary:   28.25
    =======================================================
    Time Worked Summary
    --------+---------+-----------+----------+-------------
     Monday | Tuesday | Wednesday | Thursday | Friday
    --------+---------+-----------+----------+-------------
      7.00  |   8.00  |    6.50   |   8.50   |  6.50
    ========+=========+===========+==========+=============
                                        Pay Summary
    -------------------------------------------------------
                                       Time   Pay
    -------------------------------------------------------
                         Regular:    36.50   1031.12
    -------------------------------------------------------
                         Overtime:    0.00   0.00
    =======================================================
                         Net Pay:            1031.12
    =======================================================
    
    Press any key to close this window . . .
  5. Return to your programming environment

A Class Type as a Parameter

An object of a class can be passed as argument. When creating a function, simply provide the name of a class as type followed by a name for the parameter. You can use a class from the .NET library or your own class. In the body of the function, you can ignore or use the parameter as you want. When it comes to a class passed as parameter, its public and internal members are available to the function that uses it. When calling the function, you must provide an object created from the class.

Passing an Object by Reference

You can create a function or method that uses a parameter of a class type and the argument can be passed by reference. To do this, when creating the function or method, in its parentheses, precede the class name of the parameter with the ref keyword. When calling the function or method, precede the argument with the ref keyword. As seen with primitive types, if you pass a parameter by reference, if the function or method modifies the argument, this causes it to produce an object with a new version.

Passing an Object Out

As mentioned already, another way to pass an argument by the out keyword. The concept also applies to objects passed as arguments.

Referencing an Object

A Referent

In our introduction to variables, we saw how to declare a variable using a primitive type. As a reminder, here is an example:

using static System.Console;

double side = 248.57;

WriteLine("Square Characteristics");
WriteLine("----------------------");
WriteLine("Side: {0}", side);
WriteLine("======================");

This would produce:

Square Characteristics
----------------------
Side: 248.57
======================
    
Press any key to close this window . . .

When you declare a variable in a program, the compiler reserves some space for that variable in the computer memory. The location of a variable in memory is referred to as its address. As is the case for objects, when you declare a variable of a primitive type, a portion of the computer memory is allocated for it. On the other hand, if you declare a variable using the new operator, you are letting the compiler know that when it comes time to use that variable, you will use a reference to that variable or object, not the value itself. You can make the same suggestion to the compiler about a value of a primitive type. This means that you can declare a variable using a value type (int, double, etc), but let the compiler know that you will use a reference to that variable.

To use a reference to an existing variable, declare another variable of the same type as the original variable. The data type of the new variable declaration must be preceded by the ref keyword. Here is an example:

double side = 248.57;

ref double oneOf4Sides;

To indicate the variable to which you want to refer, you must assign its name to the new ref variable. You must precede the assigned variable with the ref keyword. This can be done as follows:

double side = 248.57;

ref double oneOf4Sides = ref side;

The original variable is called a referent.

After assigning the original variable (the referent) to the referenced variable, both the original variable and the referenced variable hold the same value. This is illustrated in the following code:

using static System.Console;

double side = 248.57;

ref double oneOf4Sides = ref side;

WriteLine("Square Characteristics");
WriteLine("------------------------");
WriteLine("Original Side:   {0}", side);
WriteLine("Referenced Side: {0}", oneOf4Sides);
WriteLine("========================");

This would produce:

Square Characteristics
------------------------
Original Side:   248.57
Referenced Side: 248.57
========================
    
Press any key to close this window . . .

In the same way, you can declare as many referenced variables as you want and assign a previously declared referenced variable to each. All those referenced variables would hold the value of their referent. This can be illustrated as follows:

using static System.Console;

double side = 248.57;
    
ref double oneOf4Sides = ref side;
ref double siding = ref side;
ref double coast = ref side;
    
WriteLine("Square Characteristics");
WriteLine("------------------------");
WriteLine("Original Side:   {0}", side);
WriteLine("Referenced Side: {0}", oneOf4Sides);
WriteLine("Referenced Side: {0}", siding);
WriteLine("Referenced Side: {0}", coast);
WriteLine("========================");

This would produce:

Square Characteristics
------------------------
Original Side:   248.57
Referenced Side: 248.57
Referenced Side: 248.57
Referenced Side: 248.57
========================
        
Press any key to close this window . . .

A Read-Only Referenced Variable

Remember that, to use a referenced variable, you must assign a previously declared and initialized variable to it. For the same reason, you cannot assign a constant value to a referenced variable. If you do, the compiler would throw an error. This makes a referenced variable is a read-only item. To re-enforce this idea, you can indicate to the compiler that your referenced variable a read-only item. To do this, follow the ref keyword of the referenced variable with the readonly keyword, as in ref readonly. This can be done as follows:

using static System.Console;

double side = 248.57;
    
ref readonly double oneOf4Sides = ref side;
ref readonly double siding = ref side;
ref readonly double coast = ref side;
    
WriteLine("Square Characteristics");
WriteLine("------------------------");
WriteLine("Original Side:   {0}", side);
WriteLine("Referenced Side: {0}", oneOf4Sides);
WriteLine("Referenced Side: {0}", siding);
WriteLine("Referenced Side: {0}", coast);
WriteLine("========================");

Updating a Referenced Variable

Remember that, when you have declared and initialized a referenced variable, it holds the same value as its referent. As a consequence, if you change the value of the original variable, the value of the referenced variable also changes. This can be illustrated as follows:

using static System.Console;

double side = 248.57;

ref readonly double oneOf4Sides = ref side;
ref readonly double siding = ref side;

side = 66.93;

ref readonly double coast = ref side;
ref readonly double quad = ref side;

WriteLine("Square Characteristics");
WriteLine("------------------------");
WriteLine("Original Side:   {0}", side);
WriteLine("Referenced Side: {0}", oneOf4Sides);
WriteLine("Referenced Side: {0}", siding);
WriteLine("Referenced Side: {0}", coast);
WriteLine("Referenced Side: {0}", quad);
WriteLine("========================");

This would produce:

Square Characteristics
------------------------
Original Side:   66.93
Referenced Side: 66.93
Referenced Side: 66.93
Referenced Side: 66.93
Referenced Side: 66.93
========================

Press any key to close this window . . .

In the same way, you can change the value of a referent as many times as possible and keep in mind that its associated referenced variable is updated. Therefore, if you are planning to use the value of a referenced variable, make sure it is holding the intended value at that time. As a result, you are free to change the value of the original variable any time but use the referenced variable, knowing that its value has automatically been updated. This can be verified in the following code:

using static System.Console;

WriteLine("Square Characteristics");
WriteLine("------------------------");

double side = 248.57;
ref readonly double oneOf4Sides = ref side;

WriteLine("Original Side:   {0}", side);
WriteLine("Referenced Side: {0}", oneOf4Sides);
WriteLine("------------------------");

side = 937.866;

WriteLine("Original Side:   {0}", side);
WriteLine("Referenced Side: {0}", oneOf4Sides);
WriteLine("------------------------");

side = 66.93;

WriteLine("Original Side:   {0}", side);
WriteLine("Referenced Side: {0}", oneOf4Sides);
WriteLine("------------------------");

side = 1057.48;

WriteLine("Original Side:   {0}", side);
WriteLine("Referenced Side: {0}", oneOf4Sides);
WriteLine("========================");

In the above example, notice that only the value of the referent is updated, but every time, the referenced variable is automatically updated. The above code would produce:

Square Characteristics
------------------------
Original Side:   248.57
Referenced Side: 248.57
------------------------
Original Side:   937.866
Referenced Side: 937.866
------------------------
Original Side:   66.93
Referenced Side: 66.93
------------------------
Original Side:   1057.48
Referenced Side: 1057.48
========================

Press any key to close this window . . .

Passing a Primitive Reference to an Object

Since a referenced variable holds a real value, you can use it wherever you would use the original variable. For example, you can pass it as argument. Here is an example where a referenced variable is passed to a constructor of an object:

using static System.Console;

double side = 248.57;
    
ref double oneOf4Sides = ref side; 
Square sqr = new Square(oneOf4Sides);
    
WriteLine("Square Characteristics");
WriteLine("----------------------------");
WriteLine("Side:      {0}", sqr.Side);
WriteLine("Perimeter: {0}", sqr.CalculatePerimeter());
WriteLine("Area:      {0}", sqr.CalculateArea());
WriteLine("============================");
    
public class Square(double side)
{
    public double Side
    {
        get { return side; }
    }
    
    public double CalculatePerimeter()
    {
        return side * 4;
    }
    
    public double CalculateArea()
    {
        return side * side;
    }
}

When it comes to using a referenced variable as argument, whenever you do that, you must let the compiler know so it would update its operation(s). This can be easily done by by re-calling the items that uses the argument. Here are examples:

using static System.Console;

// Declare a variable
double side = 248.57;
// Create a referenced variable
ref readonly double oneOf4Sides = ref side;
// Pass the referenced variable to an object
Square sqr = new(oneOf4Sides);

WriteLine("Square Characteristics");
WriteLine("----------------------------");
WriteLine("Side:      {0}", sqr.Side);
WriteLine("Perimeter: {0}", sqr.CalculatePerimeter());
WriteLine("Area:      {0}", sqr.CalculateArea());
WriteLine("============================");

// Change the value of the original variable
side = 937.866;
// Let the compiler know that the value passed to the object has changed
sqr = new(oneOf4Sides);

WriteLine("Square Characteristics");
WriteLine("----------------------------");
WriteLine("Side:      {0}", sqr.Side);
WriteLine("Perimeter: {0}", sqr.CalculatePerimeter());
WriteLine("Area:      {0}", sqr.CalculateArea());
WriteLine("============================");

// Update the original variable
side = 66.93;
// Notify the compiler that the value of the object has changed
sqr = new(oneOf4Sides);

WriteLine("Square Characteristics");
WriteLine("----------------------------");
WriteLine("Side:      {0}", sqr.Side);
WriteLine("Perimeter: {0}", sqr.CalculatePerimeter());
WriteLine("Area:      {0}", sqr.CalculateArea());
WriteLine("============================");

// Update the referent
side = 1057.48;
// Let the compiler know that there is a new value for the object
sqr = new(oneOf4Sides);

WriteLine("Square Characteristics");
WriteLine("----------------------------");
WriteLine("Side:      {0}", sqr.Side);
WriteLine("Perimeter: {0}", sqr.CalculatePerimeter());
WriteLine("Area:      {0}", sqr.CalculateArea());
WriteLine("============================");

public class Square(double side)
{
    public double Side
    {
        get { return side; }
    }

    public double CalculatePerimeter()
    {
        return side * 4;
    }

    public double CalculateArea()
    {
        return side * side;
    }
}

This would produce:

Square Characteristics
----------------------------
Side:      248.57
Perimeter: 994.28
Area:      61787.04489999999
============================
Square Characteristics
----------------------------
Side:      937.866
Perimeter: 3751.464
Area:      879592.633956
============================
Square Characteristics
----------------------------
Side:      66.93
Perimeter: 267.72
Area:      4479.624900000001
============================
Square Characteristics
----------------------------
Side:      1057.48
Perimeter: 4229.92
Area:      1118263.9504
============================

Press any key to close this window . . .

Returning a Reference from a Method

In a class, you can create a method that returns a reference variable, or you can create methods that return reference variables.

Topics on Values and Objects

The Name of a Variable

In some operations you perform, you may want to access a variable, an object, a function, etc. We already that there are various ways to do that. For some operations, you may want to get the name of a variable, an object, a function, etc. To help you get such a name, the C# language provides an operator named nameof. That operator is used like a function. That is, type it, followed by parentheses. In the parentheses, type the name of the variable, function, or object. You can also access a method of a class, a property of a class, etc. Here are examples:

using static System.Console;

int number = 9383;

void Announce()
{
    WriteLine("Characteristics of Objects");
    WriteLine("===========================");
}

Announce();

House house = new House()
{
    PropertyNumber = 938_448,
    Bedrooms = 5,
    Bathrooms = 3.5,
    MarketValue = 545_760
};
                
WriteLine("Number: {0}", number);
house.Present();

WriteLine("===========================");
WriteLine("Name of Variable: {0}", nameof(number));
WriteLine("Name of Function: {0}", nameof(Announce));
WriteLine("Name of Object:   {0}", nameof(house));
WriteLine("Name of Property: {0}", nameof(house.Bathrooms));
WriteLine("Name of Method:   {0}", nameof(house.Present));
WriteLine("===========================");

internal class House
{
    public int PropertyNumber { get; set; }
    public int Bedrooms { get; set; }
    public double Bathrooms { get; set; }
    public double MarketValue { get; set; }

    public void Present()
    {
        WriteLine("Property Listing");
        WriteLine("---------------------------");
        WriteLine("Property #:   {0}", PropertyNumber);
        WriteLine("Bedrooms:     {0}", Bedrooms);
        WriteLine("Bathrooms:    {0}", Bathrooms);
        WriteLine("Market Value: {0}", MarketValue);
    }
}

This would produce:

Characteristics of Objects
===========================
Number: 9383
Property Listing
---------------------------
Property #:   938448
Bedrooms:     5
Bathrooms:    3.5
Market Value: 545760
===========================
Name of Variable: number
Name of Function: Announce
Name of Object:   house
Name of Property: Bathrooms
Name of Method:   Present
===========================

Press any key to close this window . . .

Practical LearningPractical Learning: Ending the Lesson


Previous Copyright © 2024, FunctionX Sunday 21 January 2024 Next