Fundamentals of Records

Introduction

In previous lessons, we were introduced to classes as a way to create a layout for objects. We saw other options to create objects, such as tuples and structures. Like those options, a record is a technique to combine characteristics that describe an object. There are many similarities between classes, structures, and records. We are going to review many of those issues before getting to the differences between classes and structures on one hand, and records on the other hand.

Practical LearningPractical Learning: Introducing Records

  1. Start Microsoft Visual Studio and create a new ASP.NET Core Web App named PayrollPreparation3 that uses the .NET 6.0 (Long-Term Support)
  2. In the Solution Explorer, expand wwwroot
  3. In the Solution Explorer, under wwwroot, right-click css -> Add -> New Item...
  4. In the left list of the Add New Item dialog box, under Visual C#, expand ASP.NET Core and expand Web. Click Content.
    In the middle list of the Add New Item dialog box, click Style Sheet
  5. Change the file Name to PayrollPreparation
  6. Click Add
  7. Change the document as follows:
    body {
    }
    
    .bold                             { font-weight:      bold;               }
    .text-right                       { text-align:       right;              }
    .delimiter                        { margin:           auto; 
                                        width:            650px;              }
    .top-bar                          { border-bottom:    6px solid blue;
                                        background-color: #093b12 !important; }
    .navbar-light .navbar-brand       { color:            white;              }
    .navbar-light .navbar-brand:hover { color:            yellow;             }
    .navbar-light .navbar-brand:focus { color:            khaki;              }
    .navbar-light .navbar-brand       { font-family:      Georgia, Garamond, 'Times New Roman', serif; }
    .nav-link                         { font-family:      Georgia, Garamond, 'Times New Roman', serif; }
    .common-font                      { font-family:      Georgia, Garamond, 'Times New Roman', serif; }
  8. In the Solution Explorer, right-click PayrollPreparation2 -> Add -> New Folder
  9. Type Models and press enter

Creating a Record

To create a record, you use a keyword named record. The primary formula to follow is:

access-level record name {}

As always when you create a layout for an action or an object, you can start with some options that sometimes are not required. The primary option you can apply is an access level. In many cases, an access level is not required but if you decide to use one, apply the public or internal to your record. The option(s) is (are) followed by the record keyword. As always, you must name the layout you are creating. The name of a record follows the rules of names of classes, structures, enumerations, and namespaces. As seen with those objects, a record must have a body, which starts with an opening curly bracket { and ends with a closing curly bracket }.

Practical LearningPractical Learning: Creating a Record

  1. In the Solution Explorer, right-click Models -> Add -> New Item...
  2. In the left list of the Add New Item dialog box, expand ASP.NET Core and click Code. In the middle list, click Code File
  3. Change the file Name to Employee
  4. Click Add
  5. In the empty document, type the following lines:
    namespace PayrollPreparation3.Models
    {
        internal record Employee
        {
        }
    }

Accessing a Record

When you create a record, you are simply providing a skeleton for an eventual object. To get an actual object, declare a variable of the record. You can use the name of the record as type. This is followed by a name. The name of the object follows the rules of names of variables. Add the assignment operator. A record is a reference type. As a result, you must use the new operator when creating the object. Add the name of the record and parentheses. Here is an example:

@{
    DayWork it = new DayWork();
}

@functions{
    internal record DayWork
    {
    }
}

As seen with classes and structures, when initializing the object of a record, if you are creating it using the name of the record, you can omit that name after the new operator, but the name of the record is required if you are using the var or the dynamic keyword to create the object. Here are examples:

@{
    // A classi way to create an object
    DayWork it = new DayWork();
    // An object from the name of the record and created using the "new" operator
    Canoe fun  = new();
    // A variable declared using the "var" keyword
    var leisure = new Canoe();
    // A "dynamic" object
    dynamic summer = new Canoe();
}

@functions{
    internal record Canoe
    {
    }
}

A Field in a Record

When creating a record, you should fill it with some useful members. As seen with classes and structures, the simplest thing you can do in a record is to declare a variable of a primitive type. Such a variable is also called a field. Here is an example:

public record Employee
{
    string nbr;
}

You can then use that field. Before doing that, you should apply an appropriate access level. As a reminder, if you apply the private level, the field can be accessed only by members of the same record. If you want the field to be accessed outside the record, you should apply the public or the internal levels.

Introduction to the Properties of a Record

A property is a characteristic that allows a record to communicate or exchange values with other objects. As seen with classes and structures, all options to create properties are available in a record. As a reminder, if you had added a private field to a record, you can create a complete property for it, with a get and a set clauses. Here is an example:

public record Employee
{
    int nbr;

    public int EmployeeNumber
    {
        get
        {
            return nbr;
        }

        set
        {
            nbr = value;
        }
    }
}

After creating a property, you can access it the same way you would access a property of a class or structure. Here is an example:

@page
@model Exercises.Pages.ExerciseModel
@{
    Employee staff = new Employee();

    staff.EmployeeNumber = 428_350;
}

@functions{
    public record Employee
    {
        int nbr;

        public int EmployeeNumber
        {
            get
            {
                return nbr;
            }

            set
            {
                nbr = value;
            }
        }
    }
}

<pre>Employee #: @staff.EmployeeNumber</pre>

This would produce:

Employee #: 428350

In the same way, you can use a conditional statement in a clause to accept a value, change a value, or reject a value. Here is an example:

@page
@model Exercises.Pages.ExerciseModel
@{
    Employee staff = new Employee();

    staff.EmployeeNumber = 428_350;
    staff.HourlySalary   = 8.95;
}

@functions{
    public record Employee
    {
        int nbr;
        double sal;

        public int EmployeeNumber
        {
            get { return nbr; }
            set { nbr = value; }
        }

        internal double HourlySalary
        {
            get
            {
                if (sal <= 10.00)
                    return 15.55;
                else
                    return sal;
            }

            set
            {
                sal = value;
            }
        }
    }
}

<pre>Employee #:    @staff.EmployeeNumber);
Hourly Salary: @staff.HourlySalary<pre>

This would produce:

Employee #:    428350
Hourly Salary: 15.55

In the same way, you can create one or more automatic properties in a record. Here is an example:

@{
    DayWork it = new DayWork();
}

@functions{
    internal record DayWork
    {
        public float TimeWorked { get; set; }
    }
}

An Enumerated Property

As seen with structures and classes, a field of a record can be an enumerated type. Here is an example:

public enum FilingStatus { Single, Married, Unknown }

public record Employee
{
    FilingStatus category;
}

In the same way, you can create a property of an enumeration type. Here is an example:

public enum FilingStatus { Single, Married, Unknown }

public record Employee
{
    private FilingStatus category;

    public FilingStatus FilingStatus
    {
	get
	{
	    return category;
	}

	set
	{
	    category = value;
	}
    }
}

Of course, you can create the property as an automatic one.

The Methods of a Record

Like a class or a structure, a record can have methods. You create the method exactly the same way you would create a method in a class or structure. Here is an example:

public enum FilingStatus { Single, Married, Unknown }

public record Employee
{
    private FilingStatus category;

    public FilingStatus FilingStatus
    {
        get
        {
            return category;
        }

        set
        {
            category = value;
        }
    }

    public string FirstName { get; set; }
    public string LastName  { get; set; }

    public string GetFullName()
    {
        if (LastName == "")
            throw new System.Exception("The last name is required for each employee.");

        return FirstName + " " + LastName;
    }
}

Everything else we reviewed for methods is available for records. For example, you can overload a method by passing different arguments to methods that use the same name. Here are examples:

public enum WorkCategory { Employee, Manager, Contractor, Seasonal, Unknown }

public record StoreItem
{
    public string PasswordManagement { get; set; }
    public string HiringSupervision  { get; set; }
    public string Description        { get; set; }

    // A method with a Boolean parameter
    public void Validate(bool isvalid)
    {
        if(isvalid)
            PasswordManagement = "Can Change Account Password";
        else
            PasswordManagement = "Regular Employee";
    }

    // A method with an enumerated parameter
    public void Validate(WorkCategory level)
    {
        if (level == WorkCategory.Manager)
            HiringSupervision = "Can Approve Hiring";
        else
            HiringSupervision = "Regular Employee";
    }

    // A method with two parameters
    public void Validate(int type, WorkCategory level)
    {
        switch (type)
        {
            case 2 when level == WorkCategory.Contractor:
                Description = "The job is a contract position on a temporary basis.";
                break;
            case 1 when level == WorkCategory.Seasonal:
                Description = "This is a full-time seasonal employee hired when season is at high pick.";
                break;
            case 3 when level == WorkCategory.Employee:
                Description = "The employment is be determined.";
                break;
            case 1 when level == WorkCategory.Manager:
                Description = "This is a managerial position with corporate credit cards.";
                break;
            case 2 when level == WorkCategory.Employee:
                Description = "This is a part-time employment position but put a regular payroll.";
                break;
        }
    }
}

Records and Functions

Returning a Record

Once you have created a record, it becomes a regular type. You can involve it with a function. For example, you can create a function that returns a record. To start, create a function or method whose return type is an existing record. In the body of the function, process the values any way you like. Before the closing curly bracket of the function, you must return an object that holds a record object. Here is an example:

@{
    Employee Create()
    {
        int number = 802_484;
        string fName = "Michael";
        string lName = "Tindal";
        double salary = 16.06

        return new Employee()
        {
            EmployeeNumber = number,
            FirstName = fName,
            LastName = lName,
            HourlySalary = salary
        };
    }
}

@functions{
    public record Employee
    {
        public int     EmployeeNumber { get; set; }
        public string? FirstName      { get; set; }
        public string? LastName       { get; set; }
        public double  HourlySalary   { get; set; }
    }
}

An Argumented Record

Since a record is a type, you can pass it as argument. To do that, when creating the function, specify the type of a parameter as a record type. In the body of the function, use or ignore the parameter. When calling the function, make sure you pass an argument that holds a record type. Here is an example:

@page
@model Exercises.Pages.ExerciseModel
@using static System.Console
@{
    Employee Create()
    {
        return new Employee()
        {
            EmployeeNumber = 802_484,
            FirstName = "Michael",
            LastName = "Tindal",
            HourlySalary = 16.06
        };
    }

    void Show(Employee staff)
    {
        WriteLine("=========================================");
        WriteLine("  - Human Resources -");
        WriteLine("-----------------------------------------");
        WriteLine("-=- Employee Detials -=-");
        WriteLine("=========================================");
        WriteLine($"Employee #:   {staff.EmployeeNumber}");
        WriteLine($"First Name:   {staff.FirstName}");
        WriteLine($"Last Name:    {staff.LastName}");
        WriteLine($"Gross Salary: {staff.FirstName}");
        WriteLine($"Last Name:    {staff.HourlySalary:f}");
        WriteLine("=========================================");
    }

    Employee staff = Create();

    Show(staff);
}

@functions{
    public record Employee
    {
        public int     EmployeeNumber { get; set; }
        public string? FirstName      { get; set; }
        public string? LastName       { get; set; }
        public double  HourlySalary   { get; set; }
    }
}

Here is an example of running the program:

============================================
 - Human Resources -
--------------------------------------------
          -=- Employee Detials -=-
============================================
Employee #:   913740
First Name:   Jennifer
Last Name:    Beals
Gross Salary: Jennifer
Last Name:    31.25
============================================

Records and Records

A Record as a Type

A record can be involved with other records as normally as a type can be. For example, a property of a record can be a record type. If you need to display a caption on it, at design time, in the Properties window, click Text and type a string. To do this programmatically, assign a string to the Text property of the group box control. Here is an example:

public record Identification
{
    public string Abbreviation { get; set; }
    public string GeneralName  { get; set; }
    public string ISOName      { get; set; }
}

public record State
{
    public Identification Identification { get; set; }
    public string Capital      { get; set; }
    public long   Area         { get; set; }
    public long   Population   { get; set; }
}

We have already seen that a property can be a record type. In the same way, a property of a record can be a type of another record.

Records and Inheritance

Records support inheritance, but a record can be derived only from another record. This means that you must first have a record that would serve as parent. Here is an example:

public record Employee
{
    public int    EmployeeNumber { get; set; }
    public string FirstName      { get; set; }
    public string LastName       { get; set; }
    public double HourlySalary   { get; set; }
}

public record Manager : Employee
{
    public string JobTitle         { get; set; }
    public bool   CanUnlockAccount { get; set; }
}

Inheriting from Object

If you have a good functioning class that lays a foundation that can benefit other objects, unfortunately, you cannot derive a record from it. As a result, the following code will produce an error:

public class Vehicle
{
    public int Doors { get; set; }
}

public record Tractor : Vehicle
{
    public string  ModelName    { get; set; }
    public float   EnginePower  { get; set; }
    public int     LiftCapacity { get; set; }
    public int     MowerHeight  { get; set; }
    public decimal Price        { get; set; }
}

This error is because you cannot create a record that is based on a class. There is an exception. Remember that every time you create a class in your C# application, the class is automatically derived from the object type. That concept also applies to structures and records. In fact, when you create a record, you can indicate that it derives from object. Here is an example:

@page
@model Exercises.Pages.ExerciseModel
@using static System.Console
@{
    Tractor machine = new Tractor();

    machine.ModelName    = "MW9724";
    machine.EnginePower  = 21.5f;
    machine.LiftCapacity = 754;
    machine.MowerHeight  = 60;
    machine.Price        = 13_050;

    WriteLine("Tractor Characteristics");
    WriteLine("=============================");
    WriteLine($"Model Name:     {machine.ModelName}");
    WriteLine($"Engine Power:   {machine.EnginePower} hp");
    WriteLine($"Lift Capacity:  {machine.ModelName} lbs");
    WriteLine($"Mower Height:   {machine.MowerHeight}");
    WriteLine($"Price:          {machine.Price:C}");
    WriteLine("=============================");
}

@functions{
    public record Tractor : object
    {
        public string? ModelName    { get; set; }
        public float   EnginePower  { get; set; }
        public int     LiftCapacity { get; set; }
        public int     MowerHeight  { get; set; }
        public decimal Price        { get; set; }
    }
}

This would produce:

Tractor Characteristics
=============================
Model Name:     MW9724
Engine Power:   21.5 hp
Lift Capacity:  MW9724 lbs
Mower Height:   60
Price:          $13,050.00
=============================

Probably the primary characteristic of the object class is that ot provides the primary features, mainly methods that all C# classes would need. One of these methods is the abiliby to find out whether two objects are equal. To make this happen, when you create a class, you can/must override the Equals() method. When it comes to records, the ability to compare two records objects is built in the record concept. Therefore, if you create a record, you cannot (you are not allowed to) override the Equals() method. If you do, you would receive an error.

Records and Classes

A Member of a Class Type

A member of a record, as a field or property, can be of the type of a class. You can use a .NET built-in class or you can create your own class. Then, on the body of a record, create a member whose type is a class. Here is an example:

public enum ChargeStatus { Negative, Neutral, Positive, Unknown }

// A class type
public class Nucleus
{
    // A nucleus is made of one or more protons and neutrons
    public int Protons  { get; set; }
    public int Neutrons { get; set; }
}

// A record layout
public record Atom
{
    // An atom is made of a nucleus (and one or more electrons
    public Nucleus Nucleus { get; set; }
    public int Electrons   { get; set; }
    public ChargeStatus ChargeStatus { get; set; }
}

A Record for a Class Member

The type of a member of a class, such as a field or a property, can be based on a record. When creating the member, simply specify its type as an existing record. You can then use the member as regularly as necessary. Here is an example:

public record Employee
{
    public int    EmployeeNumber { get; set; }
    public string FirstName      { get; set; }
    public string LastName       { get; set; }
}

internal record IncomeTax
{
    public int      TaxIdentifier { get; set; }
    public Employee Employee      { get; set; } = new Employee();
    public double   GrossSalary   { get; set; }
}

Records and Constructors

Introduction

Both the classes and the structures support constructors, quite in the same way (before C# 10.0, classes and structures dealt with constructors differently; for example, prior to C# 10.0, you were not allowed to create a default constructor (a constructor without a parameter) in a structure, starting with C# 10.0, you can). Constructors are a little different and particularly important in records.

So far, we didn't create constructors for our records but, like classes and constructors, a record can have constructors. In fact, if you create a record without a constructor, the compiler would create a default constructor for you. Still, if you want, you can create a default constructor in your record. Here is an example:

public record VehicleRegistration
{
    public VehicleRegistration()
    {
    }
}

Of course, when you use the default constructor to instantiate a record object, you can use the curly brackets to make a list of the properties of the record and provide a value for each. Here is an example:

@page
@model Exercises.Pages.ExerciseModel
@using static System.Console
@{
    VehicleRegistration vr = new VehicleRegistration()
    {
        TagNumber = "HPR-385",
        Make = "Ford",
        Model = "Escape",
        Year = 2020
    };
}

@functions{
    public record VehicleRegistration
    {
        int yr;
        string _nbr;
        string _make, _model;

        public VehicleRegistration()
        {
        }

        public string TagNumber
        {
            get
            {
                return _nbr;
            }

            set
            {
                _nbr = value;
            }
        }

        public string Make
        {
            get { return _make;  }
            set { _make = value; }
        }

        public string Model
        {
            get { return _model; }
            set { _model = value; }
        }

        public int Year
        {
            get { return yr;  }
            set { yr = value; }
        }
    }
}

<pre>Vehicle Registration
====================="
Tag #: @vr.TagNumber
Make:  @vr.Make
Model: @vr.Model
Year:  @vr.Year
=====================</pre>

This would produce:

Vehicle Registration
=====================
Tag #: HPR-385
Make:  Ford
Model: Escape
Year:  2020
=====================

A Parameterized Constructor

If you judge it necessary, when creating a record, you can create a constructor that takes at least one parameter. Here is an example:

public record VehicleRegistration
{
    string _nbr;

    public VehicleRegistration(string number)
    {
    }
}

You can then use such a constructor to create an object of the record. Here is an example:

@page
@model Exercises.Pages.ExerciseModel
@using static System.Console
@{
    VehicleRegistration vr = new VehicleRegistration("HPR-385");

    vr.Make = "Ford";
    vr.Model = "Escape";
    vr.Year = 2020;
}

@functions{
    public record VehicleRegistration
    {
        int yr;
        string _nbr;
        string _make, _model;

        public VehicleRegistration(string number)
        {
            _nbr = number;
        }

        . . .
    }
}

<pre>Vehicle Registration
=====================");
Tag #: @vr.TagNumber
Make:  @vr.Make
Model: @vr.Model
Year:  @vr.Year
=====================</pre>

As mentioned with classes (and valid for structures), if you create a constructor in a record and that constructor takes at least one parameter, the default constructor disappears. The solution is to manually create various constructors because, as we saw with methods, records support method overloading. To do this, create constructors that takes different numbers or different types of parameters. You can then call each constructor as needed. Here are examples:

@{
    // Using the default constructor to create an object
    VehicleRegistration vr = new VehicleRegistration()
    {
        TagNumber = "HPR-385",
        Make      = "Ford",
        Model     = "Escape",
        Year      = 2020
    };

	// Using a constructor with one parameter
    VehicleRegistration vehicle = new VehicleRegistration("937052")
    {
        Make  = "Toyota",
        Model = "Corolla",
        Year  = 1998
    };

	// A constructor with two parameters
    VehicleRegistration register = new VehicleRegistration("Buick", "LeSabre")
    {
        TagNumber = "FKE-RLW",
        Year      = 2020
    };

	// A public constructor
    VehicleRegistration registration = new VehicleRegistration("GH4-G88", "Lincoln", "Continental", 2006);
}

@functions{
    public record VehicleRegistration
    {
        int yr;
        string _nbr;
        string _make, _model;

        public VehicleRegistration()
        {
            _nbr   = "000-000";
            _make  = "Collectible";
            _model = "Classic";
            yr     = 1960;
        }

        public VehicleRegistration(string number)
        {
            _nbr = number;
        }

        public VehicleRegistration(string make, string model)
        {
            _make  = make;
            _model = model;
        }

        public VehicleRegistration(string nbr, string make, string model, int year)
        {
            _nbr   = nbr;
            _make  = make;
            _model = model;
            yr     = year;
        }

        public string TagNumber
        {
            get { return _nbr; }
            set { _nbr = value; }
        }

        public string Make
        {
            get { return _make;  }
            set { _make = value; }
        }

        public string Model
        {
            get { return _model; }
            set { _model = value; }
        }

        public int Year
        {
            get { return yr;  }
            set { yr = value; }
        }
    }
}

Initializing a Property

We know that you can create a property with a set clause, in which case you can let the clients the record assign a desired value to the property after an object of the record has been created. Here are examples of such properties:

@page
@model Valuable.Pages.CreatureModel
@using static System.Console
@{
    Canoe fun = new Canoe();

    fun.Identification = 280_385;
    fun.Make           = "Emotion";
    fun.Model          = "Wasatch ";
    fun.Length         = 13;
    fun.Price          = 479.99;
}

@functions{
    public record Canoe
    {
        int id;
        int len;
        double cost;
        string? _make;
        string? _model;

        public int Identification
        {
            get { return id; }
            set { id = value; }
        }
        
        public string? Make
        {
            get { return _make;  }
            set { _make = value; }
        }
        
        public string? Model
        {
            get { return _model; }
            set { _model = value; }
        }
        
        public int Length
        {
            get { return len;  }
            set { len = value; }
        }
        
        public double Price
        {
            get { return cost; }
            set { cost = value; }
        }
    }
}

<pre>Canoe Registration
=====================
Identifier: @fun.Identification
---------------------
Make:       @fun.Make
Model:      @fun.Model
Length:     @fun.Length
Price:      @fun.Price
=====================</pre>

This would produce:

Canoe Registration
=====================
Identifier: 280385
---------------------
Make:       Emotion
Model:      Wasatch
Length:     13
Price:      479.99
=====================

If you want to require that a certain property be given a value immediately when a record object is created, you must create an init clause insteat of a set clause. Here is an example:

public record Canoe
{
    int id;

    public int Identification
    {
        get  { return id; }
        init { id = value; }
    }
}

After doing that, the property must receive a value immediately when the record is instantiated. To make this happen, you have two options. When you create an object of the record, you can use the curly brackets to initialize the object. This can be done as follows:

@page
@model Valuable.Pages.CreatureModel
@using static System.Console
@{
    Canoe fun = new Canoe()
    {
        Make           = "Emotion",
        Model          = "Wasatch ",
        Identification = 280_385,
        Length         = 13,
        Price          = 479.99
    };
}

@functions{
    public record Canoe
    {
        int id;
        int len;
        double cost;
        string? _make;
        string? _model;
        
        public int Identification
        {
            get { return id; }
            init { id = value; }
        }
        
        public string? Make
        {
            get { return _make;  }
            set { _make = value; }
        }
        
        public string? Model
        {
            get { return _model; }
            set { _model = value; }
        }
        
        public int Length
        {
            get { return len;  }
            set { len = value; }
        }
        
        public double Price
        {
            get { return cost; }
            set { cost = value; }
        }
    }
}

<pre>Canoe Registration
=====================
Identifier: @fun.Identification
---------------------
Make:       @fun.Make
Model:      @fun.Model
Length:     @fun.Length
Price:      @fun.Price
=====================</pre>

An alternate solution is to create a constructor in the record. That constructor must have a parameter for he property. In the body of the constructor, assign the parameter to property or to its associated field. This can be done as follows:

@page
@model Valuable.Pages.CreatureModel
@using static System.Console
@{
    Canoe fun  = new Canoe(280_385);
    
    fun.Make   = "Emotion";
    fun.Model  = "Wasatch ";
    fun.Length = 13;
    fun.Price  = 479.99;
}

@functions{
    public record Canoe
    {
        int id;
        int len;
        double cost;
        string? _make;
        string? _model;
        
        public Canoe(int number)
        {
            id = number;
        }
        
        public int Identification
        {
            get { return id; }
            init { id = value; }
        }
        
        public string? Make
        {
            get { return _make;  }
            set { _make = value; }
        }
        
        public string? Model
        {
            get { return _model; }
            set { _model = value; }
        }
        
        public int Length
        {
            get { return len;  }
            set { len = value; }
        }
        
        public double Price
        {
            get { return cost; }
            set { cost = value; }
        }
    }
}

<pre>Canoe Registration
=====================
Identifier: @fun.Identification
---------------------
Make:       @fun.Make
Model:      @fun.Model
Length:     @fun.Length
Price:      @fun.Price
=====================</pre>

In the same way, in a record, you can create various properties that have init clauses. You can have a mix of properties with set and init clauses. You can also create automatic properties that usse init clauses. Remember that, when you are creating an object of the record, you must use one of both options we reviewed to initialize an caption property. Here is an example:

@page
@model Valuable.Pages.CreatureModel
@using static System.Console
@{
    Canoe fun  = new(280_385)
    {
        Make = "Emotion",
        Model = "Wasatch "
    };
    
    fun.Length = 13;
    fun.Price  = 479.99;
}

@functions{
    public record Canoe
    {
        public Canoe(int number)
        {
            Identification = number;
        }
        
        public int     Identification { get; init; }
        public string? Make           { get; init; }
        public string? Model          { get; init; }
        public int     Length         { get; set; }
        public double  Price          { get; set; }
    }
}

<pre>Canoe Registration
=====================
Identifier: @fun.Identification
---------------------
Make:       @fun.Make
Model:      @fun.Model
Length:     @fun.Length
Price:      @fun.Price
=====================</pre>

Practical LearningPractical Learning: Using Records

  1. Change the Employee record as follows:
    namespace PayrollPreparation3.Models
    {
        public record Employee
        {
            public int EmployeeNumber  { get; init; }
            public string? FirstName   { get; init; }
            public string? LastName    { get; init; }
            public double HourlySalary { get; init; }
        }
    }
  2. To add a record, in the Solution Explorer, right-click Models -> Add -> Class...
  3. In the middle list of the Add New Item dialog box, make sure Class is selected.
    Change the file Name to DayWork
  4. Click Add
  5. Change the document as follows:
    namespace PayrollPreparation3.Models
    {
        internal record DayWork
        {
            private double tm;
            private readonly Employee worker;
    
            public DayWork(Employee staff, double time)
            {
                tm     = time;
                worker = staff;
            }
    
            public double TimeWorked
            {
                get  { return tm;  }
                init { tm = value; }
            }
    
            public double RegularTime
            {
                get
                {
                    if (tm is <= 8.00)
                        return tm;
                    else
                        return 8.00;
                }
            }
    
            public double Overtime
            {
                get
                {
                    if (tm is <= 8.00)
                        return 0.00;
                    else
                        return tm - 8.00;
                }
            }
    
            public double RegularPay
            {
                get { return worker.HourlySalary * RegularTime; }
            }
    
            public double OvertimePay
            {
                get { return worker.HourlySalary * 1.50 * Overtime; }
            }
    
            public double NetPay
            {
                get { return RegularPay + OvertimePay; }
            }
        }
    }
  6. In the Solution Explorer, expand Pages and expand Shared
  7. In the Solution Explorer, under Pages and under Shared, and double-click _Layout.cshtml
  8. Change the document as follows:
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>@ViewData["Title"] - Payroll Preparation</title>
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
        <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
        <link rel="stylesheet" href="~/css/PayrollPreparation.css" asp-append-version="true" />
    </head>
    <body>
        <header>
            <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3 top-bar">
                <div class="container">
                    <a class="navbar-brand" asp-area="" asp-page="/Index">Payroll Preparation</a>
                    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                            aria-expanded="false" aria-label="Toggle navigation">
                        <span class="navbar-toggler-icon"></span>
                    </button>
                    <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                        <ul class="navbar-nav flex-grow-1">
                            <li class="nav-item">
                                <a class="nav-link text-white" asp-area="" asp-page="/Index">Home</a>
                            </li>
                            <li class="nav-item">
                                <a class="nav-link text-white" asp-area="" asp-page="/Privacy">Privacy</a>
                            </li>
                        </ul>
                    </div>
                </div>
            </nav>
        </header>
        <div class="container">
            <main role="main" class="pb-3">
                @RenderBody()
            </main>
        </div>
    
        <footer class="border-top footer text-muted">
            <div class="container">
                <p class="text-center common-font">&copy; 2022 - Payroll Preparation - <a asp-area="" asp-page="/Privacy">Privacy</a></p>
            </div>
        </footer>
    
        <script src="~/lib/jquery/dist/jquery.min.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
        <script src="~/js/site.js" asp-append-version="true"></script>
    
        @await RenderSectionAsync("Scripts", required: false)
    </body>
    </html>
  9. In the Solution Explorer, under Pages, double-click Index.cshtml
  10. Change the document as follows:
    @page
    @model IndexModel
    @using PayrollPreparation3.Models
    @using static System.Console
    @{
        string? strWeek1Monday            = null, strWeek1Tuesday            = null, strWeek1Wednesday            = null, strWeek1Thursday            = null, strWeek1Friday            = null;
        string? strWeek2Monday            = null, strWeek2Tuesday            = null, strWeek2Wednesday            = null, strWeek2Thursday            = null, strWeek2Friday            = null;
    
        string? strWeek1MondayRegularTime = null, strWeek1TuesdayRegularTime = null, strWeek1WednesdayRegularTime = null, strWeek1ThursdayRegularTime = null, strWeek1FridayRegularTime = null;
        string? strWeek2MondayRegularTime = null, strWeek2TuesdayRegularTime = null, strWeek2WednesdayRegularTime = null, strWeek2ThursdayRegularTime = null, strWeek2FridayRegularTime = null;
    
        string? strWeek1MondayOvertime    = null, strWeek1TuesdayOvertime    = null, strWeek1WednesdayOvertime    = null, strWeek1ThursdayOvertime    = null, strWeek1FridayOvertime    = null;
        string? strWeek2MondayOvertime    = null, strWeek2TuesdayOvertime    = null, strWeek2WednesdayOvertime    = null, strWeek2ThursdayOvertime    = null, strWeek2FridayOvertime    = null;
    
        string? strWeek1MondayRegularPay  = null, strWeek1TuesdayRegularPay  = null, strWeek1WednesdayRegularPay  = null, strWeek1ThursdayRegularPay  = null, strWeek1FridayRegularPay  = null;
        string? strWeek2MondayRegularPay  = null, strWeek2TuesdayRegularPay  = null, strWeek2WednesdayRegularPay  = null, strWeek2ThursdayRegularPay  = null, strWeek2FridayRegularPay  = null;
    
        string? strWeek1MondayOvertimePay = null, strWeek1TuesdayOvertimePay = null, strWeek1WednesdayOvertimePay = null, strWeek1ThursdayOvertimePay = null, strWeek1FridayOvertimePay = null;
        string? strWeek2MondayOvertimePay = null, strWeek2TuesdayOvertimePay = null, strWeek2WednesdayOvertimePay = null, strWeek2ThursdayOvertimePay = null, strWeek2FridayOvertimePay = null;
    
        string? strWeek1MondayNetPay      = null, strWeek1TuesdayNetPay      = null, strWeek1WednesdayNetPay      = null, strWeek1ThursdayNetPay      = null, strWeek1FridayNetPay      = null;
        string? strWeek2MondayNetPay      = null, strWeek2TuesdayNetPay      = null, strWeek2WednesdayNetPay      = null, strWeek2ThursdayNetPay      = null, strWeek2FridayNetPay      = null;
    
        string? strWeek1Salary            = null, strWeek2Salary             = null, strNetPay                    = null;
    
        Employee employee                 = new();
        DayWork? dwWk1Monday              = null, dwWk1Tuesday               = null, dwWk1Wednesday               = null, dwWk1Thursday               = null, dwWk1Friday               = null;
        DayWork? dwWk2Monday              = null, dwWk2Tuesday               = null, dwWk2Wednesday               = null, dwWk2Thursday               = null, dwWk2Friday               = null;
    
        if (Request.HasFormContentType)
        {
            double wk1Monday = 0.00, wk1Tuesday = 0.00, wk1Wednesday = 0.00, wk1Thursday = 0.00, wk1Friday = 0.00;
            double wk2Monday = 0.00, wk2Tuesday = 0.00, wk2Wednesday = 0.00, wk2Thursday = 0.00, wk2Friday = 0.00;
    
            int emplNbr      = 0;
            double hSalary   = 0.00;
    
            try
            {
                emplNbr       = int.Parse(Request.Form["txtEmployeeNumber"]);
            }
            catch (FormatException)
            {
                WriteLine("You must provide a valid unique number for the employee.");
            }
    
            string? firstName = Request.Form["txtFirstName"];
            string? lastName  = Request.Form["txtLastName"];
    
            try
            {
                hSalary       = double.Parse(Request.Form["txtHourlySalary"]);
            }
            catch (FormatException)
            {
                WriteLine("You must provide a valid unique number for the employee.");
            }
    
            employee = new()
            {
                EmployeeNumber = emplNbr,
                FirstName      = firstName,
                LastName       = lastName,
                HourlySalary   = hSalary
            };
    
            try { wk1Monday    = double.Parse(Request.Form["txtWeek1Monday"]);    }
            catch (FormatException) { WriteLine("You must provide a valid value for the time worked on Monday for the first week.");     }
            try { wk1Tuesday   = double.Parse(Request.Form["txtWeek1Tuesday"]);   }
            catch (FormatException) { WriteLine("You must provide a valid value for the time worked on Tuesday for the first week.");    }
            try { wk1Wednesday = double.Parse(Request.Form["txtWeek1Wednesday"]); }
            catch (FormatException) { WriteLine("You must provide a valid value for the time worked on Wednesday for the first week.");  }
            try { wk1Thursday  = double.Parse(Request.Form["txtWeek1Thursday"]);  } 
            catch (FormatException) { WriteLine("You must provide a valid value for the time worked on Thursday for the first week.");   }
            try { wk1Friday    = double.Parse(Request.Form["txtWeek1Friday"]);    } 
            catch (FormatException) { WriteLine("You must provide a valid value for the time worked on Friday for the first week.");     }
    
            try { wk2Monday    = double.Parse(Request.Form["txtWeek2Monday"]);    }
            catch (FormatException) { WriteLine("You must provide a valid value for the time worked on Monday for the second week.");    }
            try { wk2Tuesday   = double.Parse(Request.Form["txtWeek2Tuesday"]);   }
            catch (FormatException) { WriteLine("You must provide a valid value for the time worked on Tuesday for the second week.");   }
            try { wk2Wednesday = double.Parse(Request.Form["txtWeek2Wednesday"]); }
            catch (FormatException) { WriteLine("You must provide a valid value for the time worked on Wednesday for the second week."); }
            try { wk2Thursday  = double.Parse(Request.Form["txtWeek2Thursday"]);  }
            catch (FormatException) { WriteLine("You must provide a valid value for the time worked on Thursday for the second week.");  }
            try { wk2Friday    = double.Parse(Request.Form["txtWeek2Friday"]);    } 
            catch (FormatException) { WriteLine("You must provide a valid value for the time worked on Friday for the second week.");    }
    
            dwWk1Monday                  = new(employee, wk1Monday);
            dwWk1Tuesday                 = new(employee, wk1Tuesday);
            dwWk1Wednesday               = new(employee, wk1Wednesday);
            dwWk1Thursday                = new(employee, wk1Thursday);
            dwWk1Friday                  = new(employee, wk1Friday);
    
            dwWk2Monday                  = new(employee, wk2Monday);
            dwWk2Tuesday                 = new(employee, wk2Tuesday);
            dwWk2Wednesday               = new(employee, wk2Wednesday);
            dwWk2Thursday                = new(employee, wk2Thursday);
            dwWk2Friday                  = new(employee, wk2Friday);
    
            strWeek1Monday               = $"{wk1Monday:F}";
            strWeek1Tuesday              = $"{wk1Tuesday:F}";
            strWeek1Wednesday            = $"{wk1Wednesday:F}";
            strWeek1Thursday             = $"{wk1Thursday:F}";
            strWeek1Friday               = $"{wk1Friday:F}";
    
            strWeek1MondayRegularTime    = $"{dwWk1Monday.RegularTime:F}";
            strWeek1TuesdayRegularTime   = $"{dwWk1Tuesday.RegularTime:F}";
            strWeek1WednesdayRegularTime = $"{dwWk1Wednesday.RegularTime:F}";
            strWeek1ThursdayRegularTime  = $"{dwWk1Thursday.RegularTime:F}";
            strWeek1FridayRegularTime    = $"{dwWk1Friday.RegularTime:F}";
    
            strWeek1MondayOvertime       = $"{dwWk1Monday.Overtime:F}";
            strWeek1TuesdayOvertime      = $"{dwWk1Tuesday.Overtime:F}";
            strWeek1WednesdayOvertime    = $"{dwWk1Wednesday.Overtime:F}";
            strWeek1ThursdayOvertime     = $"{dwWk1Thursday.Overtime:F}";
            strWeek1FridayOvertime       = $"{dwWk1Friday.Overtime:F}";
    
            strWeek1MondayRegularPay     = $"{dwWk1Monday.RegularPay:F}";
            strWeek1TuesdayRegularPay    = $"{dwWk1Tuesday.RegularPay:F}";
            strWeek1WednesdayRegularPay  = $"{dwWk1Wednesday.RegularPay:F}";
            strWeek1ThursdayRegularPay   = $"{dwWk1Thursday.RegularPay:F}";
            strWeek1FridayRegularPay     = $"{dwWk1Friday.RegularPay:F}";
    
            strWeek1MondayOvertimePay    = $"{dwWk1Monday.OvertimePay:F}";
            strWeek1TuesdayOvertimePay   = $"{dwWk1Tuesday.OvertimePay:F}";
            strWeek1WednesdayOvertimePay = $"{dwWk1Wednesday.OvertimePay:F}";
            strWeek1ThursdayOvertimePay  = $"{dwWk1Thursday.OvertimePay:F}";
            strWeek1FridayOvertimePay    = $"{dwWk1Friday.OvertimePay:F}";
    
            strWeek1MondayNetPay         = $"{dwWk1Monday.NetPay:F}";
            strWeek1TuesdayNetPay        = $"{dwWk1Tuesday.NetPay:F}";
            strWeek1WednesdayNetPay      = $"{dwWk1Wednesday.NetPay:F}";
            strWeek1ThursdayNetPay       = $"{dwWk1Thursday.NetPay:F}";
            strWeek1FridayNetPay         = $"{dwWk1Friday.NetPay:F}";
    
            strWeek2Monday               = $"{wk2Monday:F}";
            strWeek2Tuesday              = $"{wk2Tuesday:F}";
            strWeek2Wednesday            = $"{wk2Wednesday:F}";
            strWeek2Thursday             = $"{wk2Thursday:F}";
            strWeek2Friday               = $"{wk2Friday:F}";
    
            strWeek2MondayRegularTime    = $"{dwWk2Monday.RegularTime:F}";
            strWeek2TuesdayRegularTime   = $"{dwWk2Tuesday.RegularTime:F}";
            strWeek2WednesdayRegularTime = $"{dwWk2Wednesday.RegularTime:F}";
            strWeek2ThursdayRegularTime  = $"{dwWk2Thursday.RegularTime:F}";
            strWeek2FridayRegularTime    = $"{dwWk2Friday.RegularTime:F}";
    
            strWeek2MondayOvertime       = $"{dwWk2Monday.Overtime:F}";
            strWeek2TuesdayOvertime      = $"{dwWk2Tuesday.Overtime:F}";
            strWeek2WednesdayOvertime    = $"{dwWk2Wednesday.Overtime:F}";
            strWeek2ThursdayOvertime     = $"{dwWk2Thursday.Overtime:F}";
            strWeek2FridayOvertime       = $"{dwWk2Friday.Overtime:F}";
    
            strWeek2MondayRegularPay     = $"{dwWk2Monday.RegularPay:F}";
            strWeek2TuesdayRegularPay    = $"{dwWk2Tuesday.RegularPay:F}";
            strWeek2WednesdayRegularPay  = $"{dwWk2Wednesday.RegularPay:F}";
            strWeek2ThursdayRegularPay   = $"{dwWk2Thursday.RegularPay:F}";
            strWeek2FridayRegularPay     = $"{dwWk2Friday.RegularPay:F}";
    
            strWeek2MondayOvertimePay    = $"{dwWk2Monday.OvertimePay:F}";
            strWeek2TuesdayOvertimePay   = $"{dwWk2Tuesday.OvertimePay:F}";
            strWeek2WednesdayOvertimePay = $"{dwWk2Wednesday.OvertimePay:F}";
            strWeek2ThursdayOvertimePay  = $"{dwWk2Thursday.OvertimePay:F}";
            strWeek2FridayOvertimePay    = $"{dwWk2Friday.OvertimePay:F}";
    
            strWeek2MondayNetPay         = $"{dwWk2Monday.NetPay:F}";
            strWeek2TuesdayNetPay        = $"{dwWk2Tuesday.NetPay:F}";
            strWeek2WednesdayNetPay      = $"{dwWk2Wednesday.NetPay:F}";
            strWeek2ThursdayNetPay       = $"{dwWk2Thursday.NetPay:F}";
            strWeek2FridayNetPay         = $"{dwWk2Friday.NetPay:F}";
    
            strWeek1Salary               = $"{(dwWk1Monday.NetPay + dwWk1Tuesday.NetPay + dwWk1Wednesday.NetPay + dwWk1Thursday.NetPay + dwWk1Friday.NetPay):F}";
            strWeek2Salary               = $"{(dwWk2Monday.NetPay + dwWk2Tuesday.NetPay + dwWk2Wednesday.NetPay + dwWk2Thursday.NetPay + dwWk2Friday.NetPay):F}";
    
            double netPay                = dwWk1Monday.NetPay + dwWk1Tuesday.NetPay + dwWk1Wednesday.NetPay + dwWk1Thursday.NetPay + dwWk1Friday.NetPay +
                                           dwWk2Monday.NetPay + dwWk2Tuesday.NetPay + dwWk2Wednesday.NetPay + dwWk2Thursday.NetPay + dwWk2Friday.NetPay;
            strNetPay                    = $"{netPay:F}";
        }
    }
    
    <h1 class="common-font text-center bold">Payroll Preparation</h1>       
    
    <hr />
    
    <form name="PayrollEvaluation" method="post" class="common-font">
        <h3 class="text-center bold">Employee Information</h3>
        <hr />
        <table style="width: 625px" align="center">
            <tr>
                <td style="width: 125px">@Html.Label("txtFirstName", "First Name:", new { @class = "bold" })</td>
                <td>@Html.TextBox("txtFirstName", @employee.FirstName, new { @class = "form-control" })</td>
                <td>@Html.Label("txtLastName", "Last Name:", new { @class = "bold" })</td>
                <td>@Html.TextBox("txtLastName", @employee.LastName, new { @class = "form-control" })</td>
            </tr>
            <tr>
                <td>@Html.Label("txtEmployeeNumber", "Employee #:", new { @class = "bold" })</td>
                <td>@Html.TextBox("txtEmployeeNumber", @employee.EmployeeNumber, new { @class = "form-control align-right" })</td>
                <td class="bold">Hourly Salary:</td>
                <td>@Html.TextBox("txtHourlySalary", @employee.HourlySalary, new { @class = "form-control align-right" })</td>
            </tr>
        </table>
        <hr />
        <h3 class="text-center bold">Time Sheet - Time Worked</h3>
        <hr />
        <table style="width: 625px" align="center">
            <tr style="border-bottom: 1px solid black">
                <td>&nbsp;</td>
                <td class="text-center bold">Monday</td>
                <td class="text-center bold">Tuesday</td>
                <td class="text-center bold">Wednesday</td>
                <td class="text-center bold">Thursday</td>
                <td class="text-center bold">Friday</td>
            </tr>
            <tr>
                <td style="width: 125px" class="bold">Week 1:</td>
                <td>@Html.TextBox("txtWeek1Monday",    @strWeek1Monday,    new { @class="form-control align-right" })</td>
                <td>@Html.TextBox("txtWeek1Tuesday",   @strWeek1Tuesday,   new { @class="form-control align-right" })</td>
                <td>@Html.TextBox("txtWeek1Wednesday", @strWeek1Wednesday, new { @class="form-control align-right" })</td>
                <td>@Html.TextBox("txtWeek1Thursday",  @strWeek1Thursday,  new { @class="form-control align-right" })</td>
                <td>@Html.TextBox("txtWeek1Friday",    @strWeek1Friday,    new { @class="form-control align-right" })</td>
            </tr>
            <tr>
                <td class="bold">Week 2:</td>
                <td>@Html.TextBox("txtWeek2Monday",    @strWeek2Monday,    new { @class="form-control align-right" })</td>
                <td>@Html.TextBox("txtWeek2Tuesday",   @strWeek2Tuesday,   new { @class="form-control align-right" })</td>
                <td>@Html.TextBox("txtWeek2Wednesday", @strWeek2Wednesday, new { @class="form-control align-right" })</td>
                <td>@Html.TextBox("txtWeek2Thursday",  @strWeek2Thursday,  new { @class="form-control align-right" })</td>
                <td>@Html.TextBox("txtWeek2Friday",    @strWeek2Friday,    new { @class="form-control align-right" })</td>
            </tr>
        </table>
        <hr />
        <table style="width: 300px" align="center">
            <tr>
                <td style="width: 50px">&nbsp;</td>
                <td><input type="submit" value="Evaluate Payroll" name="btnEvaluatePayroll" style="width: 150px" /></td>
            </tr>
        </table>
        <hr />
        <h3 class="text-center bold">Time and Pay Summary</h3>
        <hr />
        <table style="width: 625px" align="center">
            <tr style="border-bottom: 1px solid black">
                <td class="bold">Week 1</td>
                <td class="text-center bold">Monday</td>
                <td class="text-center bold">Tuesday</td>
                <td class="text-center bold">Wednesday</td>
                <td class="text-center bold">Thursday</td>
                <td class="text-center bold">Friday</td>
            </tr>
            <tr style="border-bottom: 1px solid black">
                <td class="bold">Regular Time:</td>
                <td class="text-center">@strWeek1MondayRegularTime</td>
                <td class="text-center">@strWeek1TuesdayRegularTime</td>
                <td class="text-center">@strWeek1WednesdayRegularTime</td>
                <td class="text-center">@strWeek1ThursdayRegularTime</td>
                <td class="text-center">@strWeek1FridayRegularTime</td>
            </tr>
            <tr style="border-bottom: 1px solid black">
                <td class="bold">Overtime:</td>
                <td class="text-center">@strWeek1MondayOvertime</td>
                <td class="text-center">@strWeek1TuesdayOvertime</td>
                <td class="text-center">@strWeek1WednesdayOvertime</td>
                <td class="text-center">@strWeek1ThursdayOvertime</td>
                <td class="text-center">@strWeek1FridayOvertime</td>
            </tr>
            <tr style="border-bottom: 1px solid black">
                <td class="bold">Regular Pay:</td>
                <td class="text-center">@strWeek1MondayRegularPay</td>
                <td class="text-center">@strWeek1TuesdayRegularPay</td>
                <td class="text-center">@strWeek1WednesdayRegularPay</td>
                <td class="text-center">@strWeek1ThursdayRegularPay</td>
                <td class="text-center">@strWeek1FridayRegularPay</td>
            </tr>
            <tr style="border-bottom: 1px solid black">
                <td class="bold">Overtime Pay:</td>
                <td class="text-center">@strWeek1MondayOvertimePay</td>
                <td class="text-center">@strWeek1TuesdayOvertimePay</td>
                <td class="text-center">@strWeek1WednesdayOvertimePay</td>
                <td class="text-center">@strWeek1ThursdayOvertimePay</td>
                <td class="text-center">@strWeek1FridayOvertimePay</td>
            </tr>
            <tr style="border-bottom: 1px solid black">
                <td class="bold">Net Pay:</td>
                <td class="text-center">@strWeek1MondayNetPay</td>
                <td class="text-center">@strWeek1TuesdayNetPay</td>
                <td class="text-center">@strWeek1WednesdayNetPay</td>
                <td class="text-center">@strWeek1ThursdayNetPay</td>
                <td class="text-center">@strWeek1FridayNetPay</td>
            </tr>
            <tr style="border-bottom: 1px solid black">
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td class="bold">Week 1 Salary:</td>
                <td class="text-center">@strWeek1Salary</td>
            </tr>
        </table>
        <hr />
        <table style="width: 625px" align="center">
            <tr style="border-bottom: 1px solid black">
                <td class="bold">Week 2</td>
                <td class="text-center bold">Monday</td>
                <td class="text-center bold">Tuesday</td>
                <td class="text-center bold">Wednesday</td>
                <td class="text-center bold">Thursday</td>
                <td class="text-center bold">Friday</td>
            </tr>
            <tr style="border-bottom: 1px solid black">
                <td class="bold">Regular Time:</td>
                <td class="text-center">@strWeek2MondayRegularTime</td>
                <td class="text-center">@strWeek2TuesdayRegularTime</td>
                <td class="text-center">@strWeek2WednesdayRegularTime</td>
                <td class="text-center">@strWeek2ThursdayRegularTime</td>
                <td class="text-center">@strWeek2FridayRegularTime</td>
            </tr>
            <tr style="border-bottom: 1px solid black">
                <td class="bold">Overtime:</td>
                <td class="text-center">@strWeek2MondayOvertime</td>
                <td class="text-center">@strWeek2TuesdayOvertime</td>
                <td class="text-center">@strWeek2WednesdayOvertime</td>
                <td class="text-center">@strWeek2ThursdayOvertime</td>
                <td class="text-center">@strWeek2FridayOvertime</td>
            </tr>
            <tr style="border-bottom: 1px solid black">
                <td class="bold">Regular Pay:</td>
                <td class="text-center">@strWeek2MondayRegularPay</td>
                <td class="text-center">@strWeek2TuesdayRegularPay</td>
                <td class="text-center">@strWeek2WednesdayRegularPay</td>
                <td class="text-center">@strWeek2ThursdayRegularPay</td>
                <td class="text-center">@strWeek2FridayRegularPay</td>
            </tr>
            <tr style="border-bottom: 1px solid black">
                <td class="bold">Overtime Pay:</td>
                <td class="text-center">@strWeek2MondayOvertimePay</td>
                <td class="text-center">@strWeek2TuesdayOvertimePay</td>
                <td class="text-center">@strWeek2WednesdayOvertimePay</td>
                <td class="text-center">@strWeek2ThursdayOvertimePay</td>
                <td class="text-center">@strWeek2FridayOvertimePay</td>
            </tr>
            <tr style="border-bottom: 1px solid black">
                <td class="bold">Net Pay:</td>
                <td class="text-center">@strWeek2MondayNetPay</td>
                <td class="text-center">@strWeek2TuesdayNetPay</td>
                <td class="text-center">@strWeek2WednesdayNetPay</td>
                <td class="text-center">@strWeek2ThursdayNetPay</td>
                <td class="text-center">@strWeek2FridayNetPay</td>
            </tr>
            <tr style="border-bottom: 1px solid black">
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td class="bold">Week 2 Salary:</td>
                <td class="text-center">@strWeek2Salary</td>
            </tr>
            <tr style="border-bottom: 1px solid black">
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td class="bold">Net Pay:</td>
                <td class="text-center">@strNetPay</td>
            </tr>
        </table>
    </form>
  11. To execute again, on the main menu, click Debug -> Start Without Debugging:

    Payroll Preparation

  12. Fill the text boxes with the following values:
    Employee Number:  297480
    First Name:       Roger
    Last Name:        Thristen
    Hourly Salary:    28.47
    Time Worked - Week 1
        Monday:       6.5
        Tuesday:      8
        Wednesday:    6
        Thursday:     8
        Friday:       7.5
    Time Worked - Week 2
        Monday:       9
        Tuesday:      8.5
        Wednesday:    10.5
        Thursday:     8
        Friday:       9.5

    Payroll Preparation

  13. Click the Evaluate Payroll button

    Payroll Preparation

  14. Close the browser and return to your programming environment

A Record With Positional Parameters

Introduction

We have learned that a record can contain one or more constructors. As a simple way to create a record, you can use the formula of a constructor. The formula to follow is:

options record name(parameter-name(s));

As always, start with one or more appropriate options. The most basic option is an access level, such as public. Use the record keyword to indicate that you are creating a record type. Add a name for the record. The name follows the rules of names of classes.

Our formula is as if you are creating a constructor of a record without creating a body delimited by curly brackets. Since a constructor is a method, you must apply parentheses to the name of the record. In the parentheses, create a parameter for each property you would have added if you had created the record in a classic way. End the statement with a semicolon. This technique is referred to as a record with positional parameters. Here is an example:

public record Battery(string PartNumber, string Identification, double Price);

This is the descritîon of a record (as a kind of class or structure) with three properties (two string properties and one double property).

The Properties of a Record With Positional Parameters

After creating a record as done above, you have a regular record equipped with properties and one constructor that takes a parameter for each property. Every property of such a record is an automatic property with a get and an init clauses. As a normal type, you can use this record to create an object and use it appropriately. For example, you can declare a variable of it and specify a value for each poisitional parameter. Remember that each parameter represents an init property. Therefore, while using a constructor, you must pass an argument for each parameter. Here is an example:

@page
@model Valuable.Pages.CreatureModel
@using static System.Console
@{
    Battery power = new Battery("928359", "ACDelco Gold 94RAGM", 164.95);
}

@functions{
    public record Battery(string PartNumber, string Identification, double Price);
}

<pre>Vehicle Battery
====================================
Part #:         @power.PartNumber
------------------------------------
Identification: @power.Identification
Price:          @power.Price
====================================</pre>

This would produce:

Vehicle Battery
=======================================
Part #:         928359
---------------------------------------
Identification: ACDelco Gold 94RAGM
Price:          164.95
=======================================

Default Positional Parameters

Remember that you must provide a parameter for each property of the record, but each property must be initialized when an object is created. We saw that there are two ways to initialize the object, and one way is with curly brackets. To use this way, you can provide a default value for each parameter. Here is an example:

public record Battery(string PartNumber = "", string Identification = "", double Price = 0.00);

This time, you can use curly brackets to initialize the object. Here is an example:

@page
@model Valuable.Pages.CreatureModel
@using static System.Console
@{
    Battery power = new Battery()    
    {
        PartNumber = "928359",
        Identification = "ACDelco Gold 94RAGM",
        Price = 164.95
    };
}

@functions{
    public record Battery(string PartNumber = "", string Identification = "", double Price = 0.00);
}

<pre>Vehicle Battery
====================================
Part #:         @power.PartNumber
------------------------------------
Identification: @power.Identification
Price:          @power.Price
====================================</pre>

With a Record Updated

A record is an immutable type. This means that, once you have created and initialized a record, you cannot change its value(s). What you can do is to make a copy of an existing record. To do this, create another record object and assign an existing record to it. You can then use the new record object like any variable. Here is an example:

@page
@model Valuable.Pages.CreatureModel
@using static System.Console
@{
    Battery power = new()    
    {
        PartNumber = "928359",
        Identification = "ACDelco Gold 94RAGM",
        Price = 164.95
    };
    
    Battery current = power;
}

@functions{
    public record Battery(string PartNumber = "", string Identification = "", double Price = 0.00);
}

<pre>Vehicle Battery
====================================
Part #:         @current.PartNumber
------------------------------------
Identification: @current.Identification
Price:          @current.Price
====================================</pre>

You can then change the value of any property you want and apply that change to the copied record. To do this, you use a keyword named with. The formula to use it is:

record-declaration with { property-1 = value-1, property-2 = value-2, property-x = value-x};

Start with a record object, such as done when declaring a record variable. Add the with keyword followed by curly brackets. End the statement with a semi-colon. Between the curly brackets, type the name of a property of the record or a list of properties. Assign the desired but appropriate value to the property. If you want to specify the values of various properties, separate them with commas. When you perform this exercise, you would get a new record with values changed on the indicated properties. The properties you don't access would keep their values given in the original record object. Here is an example:

@page
@model Valuable.Pages.CreatureModel
@using static System.Console
@{
    var power = new Battery()    
    {
        PartNumber = "928359",
        Identification = "ACDelco Gold 94RAGM",
        Price = 164.95
    };
    
    Battery current = power with { PartNumber = "479605" };
}

@functions{
    public record Battery(string PartNumber = "", string Identification = "", double Price = 0.00);
}

<pre>Vehicle Battery
====================================
Part #:         @current.PartNumber
------------------------------------
Identification: @current.Identification
Price:          @current.Price
====================================</pre>

This would produce:

Vehicle Battery
=======================================
Part #:         479605
---------------------------------------
Identification: ACDelco Gold 94RAGM
Price:          164.95
=======================================

Practical LearningPractical Learning: Ending the Lesson


Previous Copyright © 2001-2022, FunctionX Wednesday 13 October 2021 Next