Fundamentals of Mixing Classes

Introduction

In previous lessons, when we needed a class, we created it, from scratch. If we needed a different class, we created a new one, even if the new class had only slight differences with an existing class.

Practical LearningPractical Learning: Introducing Object Mixing

  1. Start Microsoft Visual Studio. Create a new Console App named Volumetrics2 that supports .NET 7.0 (Standard Term Support)
  2. To create a new folder, in the Solution Explorer, right-click Volumetrics2 -> Add -> New Folder
  3. Type Models as the name of the folder
  4. In the Solution Explorer, right-click Models -> Add -> Class...
  5. Change the name to Rectangle
  6. Click Add
  7. Change the class as follows:
    namespace Volumetrics2.Models
    {
        internal class Rectangle
        {
            public Rectangle()
            {
                Width  = 0.00;
                Height = 0.00;
            }
    
            public Rectangle(double wide, double high)
            {
                Width = wide;
                Height = high;
            }
    
            public double Width  { get; set; }
            public double Height { get; set; }
    
            public double Area
            {
                get
                {
                    return Width * Height;
                }
            }
    
            public double Perimeter
            {
                get
                {
                    return (Width + Height) * 2;
    	    }
            }
        }
    }
  8. On the main menu, click Project -> Add Class...
  9. In the middle list, make sure Class is selected.
    Change the name to Circle
  10. Click Add
  11. Change the class as follows:
    namespace Volumetrics2.Models
    {
        internal class Circle
        {
            public Circle()
            {
                Radius = 0.00;
            }
    
            public Circle(double radius)
            {
                Radius = radius;
            }
    
            public double Radius { get; set; }
    
            public double Area
            {
                get
                {
                    return Radius * Radius * 3.141592653589793238462643;
                }
            }
    
            public double Diameter
            {
                get
                {
                    return Radius * 2;
               }
            }
    
            public double Circumferemce
            {
                get { return Diameter * 3.141592653589793238462643; }
    	}
        }
    }
  12. In the Solution Explorer, right-click Models -> Add -> Class...
  13. Change the name to Cylinder
  14. Click Add

An Object as Field or Property

If you already have a useful class but need just some extra functionality, instead of creating a different class from scratch, you can create a new class but you would add only the needed extra functionality. One way you can address this issue is that, in the new class, create a member (such as a field or a property) that uses the existing class as type.

In a class, you create a member whose data type is an existing class. Here is an example of a property whose type is a class:

class Processor
{
    public string Make  { get; set; }
    public string Model { get; set; }
    public int Wattage  { get; set; }
    public double Speed { get; set; } 
}

class Computer
{
    public string Category     { get; set; }
    public string WirelessType { get; set; }
    public Processor Calculator { get; set; }
}

After creating the field or property whose type is a class, you can access the members of that type in a method of the class. To do this, type the name of the field or property, a period, and the desired member. Here is an example:

class Processor
{
    public double Speed { get; set; } 
}

class Computer
{
    public string Category      { get; set; }
    public string WirelessType  { get; set; }
    public Processor Calculator { get; set; }

    private void Describe()
    {
        Calculator.Speed = 5.33; // Ghz
    }
}

To access the members of the type outside the class, after declaring a variable of the class, type the name of the variable, a period, the name of the field or property type, a period, and the desired member. Here is an example:

Computer device = new Computer();

device.Describe();
device.Category = "Desktop";

device.Calculator.Make  = "AMD";
device.Calculator.Model = "Ryzen";

class Processor
{
    public string Make  { get; set; }
    public string Model { get; set; }
    public int Wattage  { get; set; }
    public double Speed { get; set; } 
}

class Computer
{
    public string Category      { get; set; }
    public string WirelessType  { get; set; }
    public Processor Calculator { get; set; }

    public void Describe()
    {
        Calculator = new Processor();

        Calculator.Speed = 5.33; // Ghz
    }
}

Practical LearningPractical Learning: Introducing Inheritance

  1. In the empty document, type the following code:
    namespace Volumetrics2.Models
    {
        internal class Cylinder
        {
            public Cylinder(double radius, double height)
            {
                Base = new Circle(radius);
                Lateral = new Rectangle(Base.Circumferemce, height);
            }
    
            public Circle Base { get; set; }
            public Rectangle Lateral { get; set; }
    
            public double BaseArea
            {
                get
                {
                    return Base.Area;
                }
            }
    
            public double LateralArea
            {
                get
                {
                    return Lateral.Area;
                }
            }
    
            public double Volume
            {
                get
                {
                    return BaseArea * Lateral.Height;
                }
    	}
        }
    }
  2. In the Solution Explorer, right-click Program.cs -> Rename
  3. Type Geometry (to get Geometry.cs) and press Enter
  4. Read the content of the message box and click Yes
  5. Click the Geometry.cs tab and change the document as follows:
    using Volumetrics2.Models
    using static System.Console;
    
    WriteLine("========================================");
    WriteLine("Enter the value to process the cylinder");
    Write("Width:       ");
    double radius = double.Parse(ReadLine());
    Write("Height:      ");
    double height = double.Parse(ReadLine());
    
    Cylinder cyl = new Cylinder(radius, height);
    
    WriteLine("========================================");
    WriteLine("Geometry - Cylinder Summary");
    WriteLine("========================================");
    WriteLine("Base");
    WriteLine("----------------------------------------");
    WriteLine("Diameter:      {0}", cyl.Base.Diameter);
    WriteLine("Radius:        {0}", cyl.Base.Radius);
    WriteLine("Circumference: {0}", cyl.Base.Circumferemce);
    WriteLine("Areat:         {0}", cyl.Base.Area);
    WriteLine("========================================");
    WriteLine("Lateral Side");
    WriteLine("----------------------------------------");
    WriteLine("Height:        {0}", cyl.Lateral.Height);
    WriteLine("Lateral Area:  {0}", cyl.Lateral.Area);
    WriteLine("Volume:        {0}", cyl.Volume);
    Write("========================================");
  6. To execute the project and test the application, on the main menu, click Debug -> Start Without Debugging
  7. When requested, type the Radius as 269.77 and press Enter
  8. For the Height, type 127.93 and press Enter
    ========================================
    Enter the value to process the cylinder
    Width:       269.77
    Height:      127.93
    ========================================
    Geometry - Cylinder Summary
    ========================================
    Base
    ----------------------------------------
    Diameter:      539.54
    Radius:        269.77
    Circumference: 1695.014900317837
    Areat:         228632.0848293714
    ========================================
    Lateral Side
    ----------------------------------------
    Height:         127.93
    Lateral Area:  216843.2561976609
    Volume:        29248902.612221483
    ========================================
    
    Press any key to close this window . . .
  9. Press any key to close the DOS window and return to your programming environment

Fundamentals of Inheritance

Class inheritance is the ability to create a new class that gets its primary functionality from an existing class. Before using inheritance, you must have a class. You can create it like any of the classes we have created so far.

Creating a class that is based on another class is also referred to as deriving a class from another. The first class serves as parent or base. The class that is based on another class is also referred to as child or derived.

To create a new class based on another existing class, use the following formula:

options class child-class : parent-class
{
    Body of the new class
}

Among the available options, you can start with an access level (such as public). This is followed by the class keyword and a name for the new class. To indicate that the new class is based on another class, type a colon followed by the name of the base class. For a parent class, you can first create a class. This means that you must use a class that exists aleady. Here is an example of starting a class inheritance:

class Circle
{
}

class Cylinder : Circle
{

}

If you want to be able to access the class from other languages, you can precede its name with the public keyword. Here is an example:

class Circle
{
}

public class Cylinder : Circle
{

}

After deriving a class, it becomes available and you can use it.

Practical LearningPractical Learning: Deriving From a Class

Inheritance and the Access to Class Members

Private Members

When creating a class and when dealing with inheritance, you can control what members can be accessed from outside the class and/or from only inherited members.

As introduced and used in previous lessons, a member of a class is referred to as private if it can be accessed only from within the class. To create a private member, type the private keyword to its left. A member without an access level or marked with the private keyword can be accessed only within the class, that is, only by members of the same class.

Internal and Public Members

A member of a class is internal if it can be accessed by any class of the same project. To create such a member variable, precede it with the internal keyword.

A member variable is referred to as public if it can be accessed by the classes of the same file. To create a public member variable of a class, precede it with the public keyword.

The Protected Members of a Class

Besides being made private, a member of a class can be protected to restrict its access. As seen for a private member, a protected member can be accessed by members of the same class. To let you protect a member of a class from non-deriving classes, the C# language provides a keyword named protected. Therefore, to indicate that a member is protected, set its access type to the protected keyword.

The main difference between a private and a protected member is that a protected member can be accessed by the members of its class but also the members of (a) derived class(es). Outside of those two environments, the access to a protected member would produce an error. Both the properties and the methods of a class can be protected.

If you create a member of a class and mark it as protected, the classes derived from its parent class, created in the current project or outside the current project, can access it. If you want the member to be accessed only by derived classes implemented in the same project but not the derived classes outside of the current project, mark the member as protected internal. Here are examples:

public class Person
{
    private string _name;
    private string _gdr;

    public Person(string name = "Not Available",
	          string gender = "Unknown")
    {
    	_name = name;
	_gdr  = gender;
    }

    protected internal string FullName
    {
    	get { return _name; }
	set { _name = value; }
    }

    protected internal string Gender
    {
    	get { return _gdr; }
    	set { _gdr = value; }
    }
}

Practical LearningPractical Learning: Protecting a Member of a Class

  1. Click the Circle.cs tab and change its class as follows:
    namespace Volumetrics2.Models
    {
        internal class Circle
        {
            /* This protected field can be accessed by members of this class 
             * (constructors, methods, and properties) and members of a derived class. */
            protected double radius;
    
            /* These public members can be accessed by all types of objects. */
            public Circle()
            {
                Radius = 0.00;
            }
    
            public Circle(double radius)
            {
                Radius = radius;
            }
    
            public double Radius
            {
                get
                {
                    return radius;
                }
    
                set
                {
                    radius = value;
                }
            }
    
            public double Area
            {
                get
                {
                    return Radius * Radius * 3.141592653589793238462643;
                }
            }
    
            public double Diameter
            {
                get
                {
                    return Radius * 2;
                }
            }
    
            public double Circumferemce
            {
                get { return Diameter * 3.141592653589793238462643; }
    	}
        }
    }
  2. Click the Cylinder.cs tab and change its class as follows:
    namespace Volumetrics2
    {
        public class Cylinder : Circle
        {
            public double Height { get; set; }
    
            public Cylinder(double baseRadius = 0.00, double height = 0.00)
            {
                radius = baseRadius;
                Height = height;
            }
    
            public double LateralArea
            {
                get
                {
                    return Circumferemce * Height;
                }
            }
    
            public double Volume
            {
                get
                {
                    return Area * Height;
                }
    	}
        }
    }
  3. Click the Geometry.cs tab and change it as follows:
    using Volumetrics2.Models;
    using static System.Console;
    
    
    WriteLine("========================================");
    WriteLine("Enter the value to process the cylinder");
    Write("Width:       ");
    double radius = double.Parse(ReadLine());
    Write("Height:      ");
    double height = double.Parse(ReadLine());
    
    Cylinder cyl = new Cylinder(radius, height);
    
    WriteLine("========================================");
    WriteLine("Geometry - Cylinder Summary");
    WriteLine("========================================");
    WriteLine("Base");
    WriteLine("----------------------------------------");
                /* The Diameter property is not a member of the cylinder.
                 * The diameter is inherited from the Circle class. */
    WriteLine("Diameter:      {0}", cyl.Diameter);
    WriteLine("Radius:        {0}", cyl.Radius);
                /* The Circumferemce property is not a member of the cylinder.
                 * The circumferemce is inherited from the Circle class. */
    WriteLine("Circumference: {0}", cyl.Circumferemce);
                /* The Area property is not a member of the cylinder.
                 * The area of the base is inherited from the Circle class. */
    WriteLine("Areat:         {0}", cyl.Area);
    WriteLine("========================================");
    WriteLine("Lateral Side");
    WriteLine("----------------------------------------");
    WriteLine("Height:        {0}", cyl.Height);
    WriteLine("Lateral Area:  {0}", cyl.LateralArea);
    WriteLine("Volume:        {0}", cyl.Volume);
    Write("========================================");
  4. To execute the application, on the main menu, click Debug -> Start Without Debugging
  5. For the Radius, type 963.97 and press Enter
  6. For the Height, type 517.68 and press Enter:
    ========================================
    Enter the value to process the cylinder
    Width:       963.97
    Height:      517.68
    ========================================
    Geometry - Cylinder Summary
    ========================================
    Base
    ----------------------------------------
    Diameter:      1927.94
    Radius:        963.97
    Circumference: 6056.802140561906
    Areat:         2919287.77971873
    ========================================
    Lateral Side
    ----------------------------------------
    Height:         517.68
    Lateral Area:  3135485.332126087
    Volume:        1511256897.8047922
    ========================================
    
    Press any key to close this window . . .
  7. To close the window and return to your programming environment, press A
  8. To reduce the code of a class, click the Rectangle.cs tab and change the code of the class as follows:
    namespace Volumetrics2.Models
    {
        public class Rectangle
        {
            public Rectangle()
            {
                Width  = 0.00;
                Height = 0.00;
            }
    
            public Rectangle(double wide, double high)
            {
                Width  = wide;
                Height = high;
            }
    
            public double Width        { get; set; }
            public double Height       { get; set; }
            public double Area      => Width * Height;
            public double Perimeter => (Width + Height) * 2;
        }
    }
  9. To reduce the code of another class, click the Circle.cs tab and change the class as follows:
    namespace Volumetrics2.Models
    {
        public class Circle
        {
            /* This protected field can be accessed by members of this class 
             * (constructors, methods, and properties) and members of a derived class. */
            protected double radius;
    
            public Circle() => Radius = 0.00;
            public Circle(double radius) => Radius = radius;
    
            public double Radius
            {
                get { return radius;  }
                set { radius = value; }
            }
    
            public double Area          => Radius * Radius * 3.141592653589793238462643;
            public double Diameter      => Radius * 2;
            public double Circumferemce => Diameter * 3.141592653589793238462643;
        }
    }
  10. To reduce the code of another class, click the Cylinder.cs tab and change the class as follows:
    namespace Volumetrics2
    {
        public class Cylinder : Circle
        {
            public double Height { get; set; }
    
            public Cylinder(double baseRadius = 0.00, double height = 0.00)
            {
                radius = baseRadius;
                Height = height;
            }
    
            public double LateralArea => Circumferemce * Height;
            public double Volume      => Area * Height;
        }
    }
  11. To execute the application to make sure no error was created, on the main menu, click Debug -> Start Without Debugging
  12. For the Radius, type 381.66 and press Enter
  13. For the Height, type 246.38 and press Enter:
    ========================================
    Enter the value to process the cylinder
    Width:       381.66
    Height:      246.38
    ========================================
    Geometry - Cylinder Summary
    ========================================
    Base
    ----------------------------------------
    Diameter:      763.32
    Radius:        381.66
    Circumference: 2398.040504338161
    Areat:         457618.0694428513
    ========================================
    Lateral Side
    ----------------------------------------
    Height:        246.38
    Lateral Area:  590829.2194588361
    Volume:        112747939.9493297
    ========================================
    
    Press any key to close this window . . .

Primary Characteristics of Inheritance

Initializing an Object of a Derived Class

If you declare a variable of a class that is derived, the variable has access to the public and internal member of its direct class. The variable has direct access also to the public and internal member of the parent(s) of its class. You can initialize the variable by accessing each member individually. As an alternative, you use the curly brackets to initialize the object.

Practical LearningPractical Learning: Initializing an Object of a Derived Class

  1. Change the Geometry.cs document as follows:
    using Volumetrics2.Models;
    using static System.Console;
    
    Cylinder Initialize()
    {
        WriteLine("========================================");
        WriteLine("Enter the value to process the cylinder");
        Write("Width:       ");
        double radius = double.Parse(ReadLine());
        Write("Height:      ");
        double height = double.Parse(ReadLine());
    
        Cylinder cylinder = new Cylinder(radius, height);
    
        return cylinder;
    }
    
    Geometry geo = new Geometry();
    Cylinder cyl = geo.Initialize();
    
    WriteLine("========================================");
    WriteLine("Geometry - Cylinder Summary");
    WriteLine("========================================");
    WriteLine("Base");
    WriteLine("----------------------------------------");
    /* The Diameter property is not a member of the cylinder.
     * The diameter is inherited from the Circle class. */
    WriteLine("Diameter:      {0}", cyl.Diameter);
    WriteLine("Radius:        {0}", cyl.Radius);
    /* The Circumferemce property is not a member of the cylinder.
     * The circumferemce is inherited from the Circle class. */
    WriteLine("Circumference: {0}", cyl.Circumferemce);
    /* The Area property is not a member of the cylinder.
     * The area of the base is inherited from the Circle class. */
    WriteLine("Areat:         {0}", cyl.Area);
    WriteLine("========================================");
    WriteLine("Lateral Side");
    WriteLine("----------------------------------------");
    WriteLine("Height:         {0}", cyl.Height);
    WriteLine("Lateral Area:  {0}", cyl.LateralArea);
    WriteLine("Volume:        {0}", cyl.Volume);
    Write("========================================");
  2. To make sure there is no error, press Ctrl + F5
  3. For the Radius, type 1429.67 and press Enter
  4. For the Height, type 688.38 and press Enter:
    ========================================
    Enter the value to process the cylinder
    Width:       1429.67
    Height:      688.38
    ========================================
    Geometry - Cylinder Summary
    ========================================
    Base
    ----------------------------------------
    Diameter:      2859.34
    Radius:        1429.67
    Circumference: 8982.88153811544
    Areat:         6421278.12429875
    ========================================
    Lateral Side
    ----------------------------------------
    Height:         688.38
    Lateral Area:  6183635.993207906
    Volume:        4420279435.204774
    ========================================
    
    Press any key to close this window . . .
  5. To close the window and return to Microsoft Visual Studio, press Z

Creating a Grand-Child

You can create a class that adds some functionality to a class that itself is derived from another. One approach is to proceed as we saw in our introduction to mixing classes: In the new class, create a member that is of the child class type. Here is an example:

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

class Student : Person
{
    public int StudentNumber { get; set; }
    public string Grade { get; set; }
}

class ReportCard
{
    public string SchoolYear { get; set; }
    public Student Pupil { get; set; }
}

Otherwise, you can create a class that is derived from a class that itself is based on another class. Here is an example:

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Gender { get; set; }
    public string DateOfBirth { get; set; }
}

class Adult : Person
{
    public string HighestEducationLevel { get; set; }
    public string MaritalStatus { get; set; }
}

class Employee : Adult
{
    public int EmployeeNumber { get; set; }
    public double HourlySalary { get; set; }
    public string DateHired { get; set; }
}

In the same way, you can create a class that is based on class that is itself is based on a class that is derived from another class that in turn descends from another class, and so on.

Intermediate Characteristics of Inheritance

A Public Class

Sometimes, you will work on a solution that includes many projects. Sometimes too, you will create classes that you want to use in different projects. To make sure that a class is made for that type of exchange, create it as a public class. To do that, mark the class with the public keyword, which is written on the left side of the class keyword. Here is an example:

public class Book
{
    
}

If you are creating a class that will be used in one project, the public keyword in not required. Still, in that case, you can apply the public keyword if you want (it doesn't have any negative impact).

Remember that you can create many classes in the same document. In that case, you can mark some classes with the public keyword and omit it for some other classes. Here is an example:

class School
{

}

public class Country
{

}

class PoliticalParty
{

}

You can mark a partial class with an access level. In this case, you can write the public keyword to the left of the partial keyword. Here is an example:

public partial class Person
{
    
}

Inheritance with a Public Class

If you create a class that is based on another class, if you decide to make the child class public, the compiler will check the access level of the parent class. If the parent is not made public, you would receive an error. The suggestion is to either make the parent class public or not apply the access level to the classes. Here is an example:

public class Schaool
{

}

public class Country
{

}

Partial Classes and Inheritance

If you create a class as a partial one, you can create another class based on it. Here is an example:

partial class Road
{
    
}

class Highway : Road
{
    
}

The child class doesn't have to be partial, although it can be. You can create a partial class that is derived from a non-partial class. Here is an example:

class EletronicMemory
{
    public int Capacity { get; set; }
}

partial class HardDrive : EletronicMemory
{
    public string Make { get; set; }
    public string Model { get; set; }
}

You can also create a partial class that is derived from a partial class. Here is an example:

partial class Road
{

}

partial class Interstate : Road
{

}

Remember that you can mark a partial class with an access level. This is also valid in inheritance. Here are examples:

public partial class Road
{

}

public partial class Interstate : Road
{

}

Namespaces and Inheritance

Imagine you had created a class named Element in a namespace named Chemistry as follows:

namespace Chemistry
{
    class Element
    {
    }
}

To derive a class from a class that belongs to a namespace, type the name of the namespace, followed by the period operator ".", and followed by the name of the base namespace. Here is an example:

namespace Chemistry
{
    class Element
    {
    }
}

class Isotope : Chemistry.Element
{
    public int NeutronNumber { get; set; }
}

If you need to call the class that was defined in a different namespace, you can qualify its name with the period operator. Here is an example:

namespace Chemistry
{
    class Element
    {
    }
}

class Isotope : Chemistry.Element
{
    public int NeutronNumber { get; set; }
}

class Exercise
{
    public void Create()
    {
	    Chemistry.Element h = new Chemistry.Element();
    }
}

Alternatively, to use the contents of a namespace, prior to calling a member of that namespace, you can type the using keyword followed by the name of the namespace. Here is an example:

using Chemistry;

class Isotope : Element
{
    public int NeutronNumber { get; set; }
}

class Exercise
{
    public void Create()
    {
	    Element h = new Element();
    }
}

Consider the following class named Matter and that is created in a nested namespace:

namespace Chemistry
{
    class Element
    {
    }

    namespace Atoms
    {
        namespace Nucleons
        {
            class Proton
            {
                public string Symbol { get; set; }
            }

            class Neutron
            {
            }
        }

        public class Matter
        {
            public double Mass { get; set; }
        }
    }
}

If you want to create a class that is based on a class in a nested namespace, you can qualify its name. Here is an example:

class Atom : Chemistry.Atoms.Matter
{
    public Chemistry.Element Element { get; set; }
    public Nucleus Nucleus { get; set; }
}

Practical LearningPractical Learning: Ending the Lesson


Previous Copyright © 2001-2023, C# Key Saturday 29 April 2023, 23:44 Next