Introduction to Constructors and Properties

Initializing a Property Reader

A read property is referred to as read-only property because the clients of the class can only retrieve the value of the property but they cannot change it. Therefore, if you create a read property, you should provide the users with the ability to primarily specify the value of the field it represents. This would be a way to initialize the property readers.

To initialize a property reader, you can use a constructor of the class. To start, when creating the constructor, add a parameter to it. The parameter must be the same type as the property you want to initialize. Then, in the body of the constructor, assign the parameter to the private field associated with the property. This can be done as follows:

@functions{
    public class Square
    {
        private double _side;
        
        public double Side
        {
            get
            {
                return _side;
            }
        }
        
        public Square(double s)
        {
            _side = s;
        }
    }
}

Once a read property has been created, other classes can access it, for example they can read its value. Here is an example:

@page
@model PracticalLearning.Pages.TimeSheetModel
@{
    Square sq = new(248.731);
}

@functions{
    public class Square
    {
        private double _side;
        
        public double Side
        {
            get
            {
                return _side;
            }
        }
        
        public Square(double s)
        {
            _side = s;
        }
    }
}

<pre>=========================
Geometry - Square
-------------------------
Side:      @sq.Side
=========================</pre>

This would produce:

=========================
Geometry - Square
-------------------------
Side:      248.731
=========================

Initializing an Automatic Read-Only Property

Remember that an automatic property is one that is created with only the get or set contextual keyword without a body. An automatic read-only property is a property created with the get constextual keyword without a body. Here is an example:

@functions{
    public class TrafficCamera
    {
        public string Location { get; }
    }
}

If you want to initialize an automatic read-only property, create a constructor. In the body of a constructor, assign the desired value to the property. Here is an example:

@functions{
    public class TrafficCamera
    {
        public string Location { get; }

        public TrafficCamera()
        {
            Location = "Randolph Road and Jamison Avenue";
        }
    }
}

You cannot use a function or a method other than a constructor to initialize an automatic read-only property. As an alternative, to initialize an automatic read-only property, instead of using a constructor, after the curly brackets of the property, assign the desired default value. Here is an example:

@functions{
    public class Depreciation
    {
    	public double Cost { get; } = 10000;
    }
}

Initializing an Automatic Property

To initialize an automatic property, you can create a constructor that uses a parameter for the property. In the body of the constructor, assign the argument to the property. Here is an example:

@functions{
    public class Element
    {
    	public int AtomicNumber { get; set; }

	public Element(int number)
    	{
            AtomicNumber = number;
    	}
    }
}

In the same way, if you want the property to be initialized with any value of your choice, you don't have to include a corresponding value in the constructor. Instead, in the body of the constructor, you can assign any value you want. Here is an example:

@functions{
    public class Element
    {
    	public int AtomicNumber { get; set; }

    	public Element()
    	{
            AtomicNumber = 12;
    	}
    }
}

Assigning a Default Value to an Automatic Property

Instead of initializing an automatic property in a constructor, you can assign the desired value after the curly brackets of the property. Here is an example:

@functions{
    public class Element
    {
    	public int AtomicNumber { get; set; } = 12;
    }
}

A Required Initialized Property

Introduction

Consider a read-only property as follows:

@page
@model Valuable.Pages.ExerciseModel
@{
    House residence = new();
}

@functions
{
    public class House
    {
        int price;
        
        public int MarketValue
        {
            get
            {
                return price;
            }
        }
    }
}

<pre>Market Value: @residence.MarketValue</pre>

This would produce:

Market Value: 0

Obviously, this read-only property is not initialized, and there is no way to initialize the property. Of course, the alternative is to add a set clause and be able to initialize the property from there. Here is an example:

@page
@model Valuable.Pages.ExerciseModel
@{
    House residence = new();
}

@functions
{
    public class House
    {
    	int price;

        public int MarketValue
    	{
            get
            {
            	return price;
            }

            set
            {
                price = value;
            }
	}
    }
}

<pre>Market Value: @residence.MarketValue</pre>

Notice that the above code makes it possible to initialize the property, but the property was not used without being initialized. Of course, now that the property has a set clause, you can initialize it. Here is an example:

@page
@model Valuable.Pages.ExerciseModel
@{
    House residence = new();

    residence.MarketValue = 450_000;
}

@functions
{
    public class House
    {
    	int price;

        public int MarketValue
        {
            get
            {
                return price;
            }

            set
            {
                price = value;
	    }
        }
    }
}

<pre>Market Value: @residence.MarketValue</pre>

This would produce:

Market Value: 450000

If the property was not initialized, this means that if you did not, or forgot to, initialize the property, or you made a mistake of using or accessing a property that was not initialized, your code could lead to unpredictable behavior. There is an alternative or a solution to this type of situation.

Creating a Read-Write Property Initializer

Instead of the set contextual keyword, an alternative to create a property reader is with a contextual keyword named init. You primarily use it the same way you would proceed to create a set clause. Here is an example:

@page
@model Valuable.Pages.ExerciseModel
@{
    House residence = new();
}

@functions
{
    public class House
    {
    	int price;

        public int MarketValue
        {
            get
            {
                return price;
            }

            init
            {
                price = value;
            }
	}
    }
}

<pre>Market Value: @residence.MarketValue</pre>

This time, to avoid the mistake of accessing a property that was not properly initialized, you must use a constructor (there are other means to initialize this type of property but we haven't studied them yet). To do this, create a constructor that uses a parameter that is the same type as the property. In the body of the constructor, initialize the property, which can be done by assigning it to the field that corresponds to the property. Then, when you create an object of the class, in the parentheses of the constructor, you must pass a value that initializes the property. Here is an example:

@page
@model Valuable.Pages.ExerciseModel
@{
    House residence = new House(450_000);
}

@functions
{
    public class House
    {
        int price;
        
        public int MarketValue
        {
            get
            {
                return price;
            }
            
            init
            {
                price = value;
            }
        }

        public House(int cost)
        {
            price = cost;
        }
    }
}

<pre>Market Value: @residence.MarketValue</pre>

This would produce:

Market Value: 450000

Remember that if you are using the constructor to declare the variable, you can omit the constructor after the new operator. As a result, the above code could have been written:

@page
@model Valuable.Pages.ExerciseModel
@{
    House residence = new(450_000);
}

@functions
{
    public class House
    {
        int price;
        
        public int MarketValue
        {
            get
            {
                return price;
            }
            
            init
            {
                price = value;
            }
        }

        public House(int cost)
        {
            price = cost;
        }
    }
}

<pre>Market Value: @residence.MarketValue</pre>

An Automatic Property Initializer

We have already seen how to create an automatic read-write property with get and set clauses. Here is an example:

@page
@model Valuable.Pages.ExerciseModel
@{
    House residence = new();
    residence.MarketValue = 450_000;
}

@functions
{
    public class House
    {
        public int MarketValue
        {
            get;
            set;
        }
    }
}

<pre>Market Value: @residence.MarketValue</pre>

Notice that you can initialize the property because it has a set accessor. In the same way, you can create an automatic property with get and init clauses. Here is an example:

@page
@model Valuable.Pages.ExerciseModel
@{
}

@functions
{
    public class House
    {
        public int MarketValue
        {
            get;
            init;
        }
    }
}

This time, if you want to initialize the property, you can (must) use a constructor that uses a parameter that you will assign to the property. Here is an example:

@page
@model Valuable.Pages.ExerciseModel
@{
    House residence = new House(450_000);
}

@functions{
    public class House
    {
        public int MarketValue
        {
            get;
            init;
        }
        
        public House(int price)
        {
            MarketValue = price;
        }
    }
}

<pre>Market Value: @residence.MarketValue</pre>

Interfaces and Property Initializers

We have seen that you can create a class that doesn't have a constructor even if that class implements an interface. In an interface, you can create an init property. Here is an example:

@functions{
    public interface IPolygon    
    {
        int Edges         { get; }
        double Side       { get; init; }
        int InternalAngle { get; }
        double Perimeter  { get; }
        double Area       { get; }

        double CalculateInscribedRadius();
        double CalculateCircumscribedRradius();
    }
}

If you create an init property in an interface, any class that implements that interface must have at least one constructor and you must use that constructor to initialize the property. Here is an example:

@page
@model PracticalLearning.Pages.GeometryModel
@{
    EquilateralTriangle et = new(1336.069);
}

@functions{
    public interface IPolygon
    {
        int Edges         { get; }
        double Side       { get; init; }
        int InternalAngle { get; }
        double Perimeter  { get; }
    }
    
    public class EquilateralTriangle : IPolygon
    {
        public EquilateralTriangle(double edge)
        {
            Side = edge;
        }
        
        public int Edges
        {
            get { return 3; }
        }
        
        public double Side { get; init; }
        
        public int InternalAngle
        {
            get { return 60; }
        }
        
        public double Perimeter
        {
            get { return Side * Edges; }
        }
    }
}

<pre>=================================
Geometry - Equilateral Triangle
---------------------------------
Side:           @et.Side
---------------------------------
Internal Angle: @et.InternalAngle
Perimeter:      @et.Perimeter
=================================</pre>

This would produce:

=================================
Geometry - Equilateral Triangle
---------------------------------
Side:           1336.069
---------------------------------
Internal Angle: 60
Perimeter:      4008.207
=================================

Remember that, to reduce the the code of a class, you can use the the => operator on some properties and methods. Here are examples:

@functions{
    public interface IPolygon
    {
        int Edges         { get; }
        double Side       { get; init; }
        int InternalAngle { get; }
        double Perimeter  { get; }
    }
    
    public class EquilateralTriangle : IPolygon
    {
        public EquilateralTriangle(double edge) => Side = edge;
        
        public int Edges => 3;
        
        public double Side { get; init; }
        
        public int InternalAngle => 60;
        public double Perimeter  => Side * Edges;
    }
}

We already know that you can declare a variable using an interface. If you do that (if you declare a variable using an interface), you can access only the members of the interface. The non-interface members of the class would not be available.

Introduction to Classes and Objects

A Class Type as Parameter

Consider a class as follows:

@functions{
    public class Element
    {
        internal string ElementName  { get; set; }
        internal string Symbol       { get; set; }
        internal int    AtomicNumber { get; set; }
        internal double AtomicWeight { get; set; }

        public Element()                 { }
        public Element(string symbol) => Symbol = symbol;
        public Element(int number)    => AtomicNumber = number;

        public Element(int number, string symbol, string name, double mass)
        {
            Symbol       = symbol;
            ElementName  = name;
            AtomicWeight = mass;
            AtomicNumber = number;
        }
    }
}

An object of a class can be passed as argument. For example, a class type can be used as a parameter of a function or a method of another class. When creating the function or method, 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. As mentioned already, in the body of the function or method, you can ignore or use the parameter. When it comes to a class passed as parameter, its public and internal members are available to the method that uses it. When calling the function or method, you must provide an object created from the class. Here is an example:

@functions{
    public class Element
    {
        internal string ElementName  { get; set; }
        internal string Symbol       { get; set; }
        internal int    AtomicNumber { get; set; }
        internal double AtomicWeight { get; set; }

        public Element()                 { }
        public Element(string symbol) => Symbol = symbol;
        public Element(int number)    => AtomicNumber = number;

        public Element(int number, string symbol, string name, double mass)
        {
            Symbol       = symbol;
            ElementName  = name;
            AtomicWeight = mass;
            AtomicNumber = number;
        }
    }

    void Present(Element obj)
    {
        
    }
}

Returning an Object

A function or method can be made to produce an object. When creating the function, specify the name of the desired class before the name of the function. You can use your own class or use one of the many classes that come with the .NET library. In the body of the function or method, you can declare a variable of the class and initialize it. Before the closing bracket of the function, you must use the return keyword followed by the object and a semicolon. Here is an example:

@functions{
    public class Square
    {
        private double s;

        public double Side
        {
            set
            {
                s = value;
            }

            get
            {
                return s;
            }
        }

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

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

    Square Create()
    {
        Square sqr = new Square();

        sqr.Side = 928.49;

        return sqr;
    }
}

Calling a Method that Returns an Object

To call a function or method that returns an object, you can first declare a variable of the class's return type and later assign the call to it. Here is an example:

@page
@model PracticalLearning.Pages.GeometryModel
@{
    Square shape = Create();
}

@functions{
    public class Square
    {
        private double s;

        public double Side
        {
            set
            {
                s = value;
            }

            get
            {
                return s;
            }
        }

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

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

    Square Create()
    {
        Square sqr = new Square();

        sqr.Side = 928.49;

        return sqr;
    }
}

<pre>=======================
Geometry - Square
-----------------------
Side:      @shape.Side
-----------------------
Perimeter: @shape.CalculatePerimeter()
Area:      @shape.CalculateArea()
=======================</pre>

This would produce:

=======================
Geometry - Square
-----------------------
Side:      928.49
-----------------------
Perimeter: 3713.96
Area:      862093.6801
=======================

A Class Type as Reference

You can create a function or method that uses a parameter of a class type and the argument can be passed as reference. To do this, when creating the function or method, in its parentheses, precede the data type of the parameter with the ref keyword. When calling the function or method, type the ref keyword on the left side of the argument. 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. Here is an example:

@page
@model PracticalLearning.Pages.TimeSheetModel
@{
    Square shape = new Square();
    
    Create(ref shape);
}

@functions{
    public class Square
    {
        private double s;

        public double Side
        {
            set { s = value; }
            get { return s;  }
        }

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

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

    void Create(ref Square sqr)
    {
        sqr = new Square();

        sqr.Side = 928.49;
    }
}

<pre>=======================
Geometry - Square
-----------------------
Side:      @shape.Side
-----------------------
Perimeter: @shape.CalculatePerimeter()
Area:      @shape.CalculateArea()
=======================</pre>

Returning an Object From a Class's Own Method

You can create a method that returns an instance of its own class. To start, on the left side of the method, enter the name of the class. Here is an example:

@functions{
    public class Employee
    {
        public Employee Create()
        {
        }
    }
}

There are various ways you can deal with the method. If you want to return a new value of the class, you can declare an instance of the class, initialize it, and then return it. Here is an example:

@functions{
    public class Employee
    {
        public int emplNbr;
        public string fName;
        public string lName;
        public double salary;

        public Employee Create()
        {
	        Employee staff = new Employee();

            staff.emplNbr = 947059;
	        staff.fName = "Paull";
	        staff.lName = "Motto";
            staff.salary = 54925;

            return staff;
	    }
    }
}

Another technique consists of declaring an instance of the class and initialize its fields with those of the class. Here is an example:

@functions{
    public class Employee
    {
        public int emplNbr;
        public string fName;
        public string lName;
        public double salary;

        public Employee Create()
        {
       	    Employee staff = new Employee();

            staff.emplNbr = emplNbr;
	        staff.fName = fName;
            staff.lName = lName;
	        staff.salary = salary;

	        return staff;
	    }
    }
}

Most of the time, this technique may not be very useful. As an alternative, you can pass some parameters to the method and then initialize the fields of the class with those parameters. After doing this, when calling the method, you can assign it to an object of the same class.

Using the Returned Object of a Method

If you have a class that contains a method that returns an object of the type of the other class, you can call such a method to get a reference to the other class. That reference, used as an object, can be used as a valid object gotten from the first class.

A Read-Only Object Type

We already know that if we create a field that is a class type, we must find a way to initialize the field before it. Such an intialization can be done in a constructor. When studying fields created from primitive types, we saw that, to indicate that the field is initialized in a constructor of the class where the field if created, you can mark that field with as readonly. This is also valid for a field of a class type.

Passing a Class in, and Returning an Object from, its Own Method

In a class, you can create a method that both uses a parameter that is of the type of its own class and returns an object that is the type of its own class. Here is an example:

@functions{
    public class Circle
    {
        public Circle Create(Circle cir)
        {
    	}
    }
}

As mentioned already, in the body of the method, the parameter has access to all members of the class. Before exiting the method, make sure you return an object that is the type of the class. Here is an example:

@functions{
    public class Circle
    {
        public Circle Create(Circle cir)
        {
            Circle rounder = new Circle();

            return rounder;
	}
    }
}

Involving a Class in its Own Members

The Type of a Field as its Own Class

In a class, you can create a field that is the type of its own class. Here is an example:

@functions{
    public class Employee
    {
        public int EmplNbr;
        public string FName;
        public string LName;
        public double Salary;

        Employee staff;
    }
}

Before using the field, you must initialize it. You have many options. You can initialize the field directly in the body of the class. Here are examples:

@functions
{
    public class Element
    {
        internal string ElementName  { get; set; }
        internal string Symbol       { get; set; }
        internal int    AtomicNumber { get; set; }
        internal double AtomicWeight { get; set; }

        public Element(int number, string symbol, string name, double mass)
        {
            Symbol       = symbol;
            ElementName  = name;
            AtomicWeight = mass;
            AtomicNumber = number;
        }

        Element Si = new Element(14, "Si", "Silicon", 28.085);
        Element P = new Element(number: 15, symbol: "P", name: "Phosphorus", mass: 30.974);
        Element S = new(16, "S", "Sulfur", 32.06);
        Element Cl = new(number: 17, symbol: "Cl", name: "Chlorine", mass: 35.45);
        Element Ar = new(name: "Argon", number: 18, symbol: "Ar", mass: 39.948);
        Element K = new Element()
        {
            AtomicNumber = 19,
            Symbol = "K",
            AtomicWeight = 39.098,
            ElementName = "Potassium"
        };
    }
}

If you do this, the field can be accessed by any member of the same class. If you make the field public or internal, if you decide to use it outside the class, you can access the public and internal members of the class through that field.

Passing a Class Type to its Own Method

An instance of a class can be passed as an argument to one of its own methods. To do this, you primarily pass the argument as if it were any type. Here is an example:

@functions{
    public class HotelRoom
    {
        public void Display(HotelRoom room)
        {
	}
    }
}

In the body of the method, you can do whatever you want. You can, or you may not, use the parameter. Still, if you decide to use the parameter, know that all the other members of the class are accessible through the parameter. One of the simplest ways you can use the parameter is to assign each of its values to the equivalent member of the class. Here is an example:

@functions{
    public class HotelRoom
    {
        private string roomNbr;
        private int    capacity;
        private string roomType;
        private double rate;

        public void Display(HotelRoom room)
        {
       	    roomNbr = room.roomNbr;
	        capacity = room.capacity;
    	    roomType = room.roomType;
	        rate = room.rate;
	    }
    }
}

When calling the method, make sure you pass an instance of the class to it. You can first create and define an object of the class, then pass it.

A Class Type as a Parameter to its Own Constructor

Just like a class can be used as the type of a parameter in one of its own methods, a class type can be used as a parameter to one of its own constructors. This can be done as follows:

@functions{
    public class HotelRoom
    {
        public HotelRoom(HotelRoom sample)
        {
	}
    }
}

Instead of a formal method, you can use a constructor of the class to pass an instance of the same class. Then, in the constructor, use the argument as you see fit, knowing that all the members of the class are available.

Returning an Object From a Class's Own Method

You can create a method that returns an instance of its own class. To start, on the left side of the method, enter the name of the class. Here is an example:

@functions{
    public class Employee
    {
        public Employee Create()
        {
	    }
    }
}

There are various ways you can deal with the method. If you want to return a new value of the class, you can declare an instance of the class, initialize it, and then return it. Here is an example:

@functions{
    public class Employee
    {
        int emplNbr;
        string fName;
        string lName;
        double salary;

        public Employee Create()
        {
            Employee staff = new Employee();

            staff.emplNbr = 947059;
            staff.fName = "Paull";
            staff.lName = "Motto";
            staff.salary = 54925;

            return staff;
	    }
    }
}

Another technique consists of declaring an instance of the class and initialize its fields with those of the class. Here is an example:

@functions{
    public class Employee
    {
        int emplNbr;
        string fName;
        string lName;
        double salary;

        public Employee Create()
        {
            Employee staff = new Employee();

            staff.emplNbr = emplNbr;
            staff.fName = fName;
            staff.lName = lName;
            staff.salary = salary;

            return staff;
	    }
    }
}

Most of the time, this technique may not be very useful. As an alternative, you can pass some parameters to the method and then initialize the fields of the class with those parameters. After doing this, when calling the method, you can assign it to an object of the same class.


Previous Copyright © 2001-2022, C# Key Monday 27 December 2021 Next