Generic Classes and Inheritance

Introduction

Consider the following geometric figures:

Square Rectangle Trapezoid Parallelogram
Square Rectangle Trapezoid Parallelogram

Notice that these are geometric figures with each having four sides. From what we know so far, we can create a base class to prepare it for inheritance. If the class is very general, we can make it a generic one. We can set a data type as an unknown type, anticipating that the dimensions of the figure can be considered as integer or double-precision types. Here is an example:

@functions{
    public class Quadrilateral<T>
    {
        public T basis;
        public T height;
        public string name;
        
        public Quadrilateral(string _name_ = "Quadrilateral")
        {
            name = _name_;
        }
        
        public Quadrilateral(T _base_, T _height_)
        {
            name = "Quadrilateral";
            basis = _base_;
            height = _height_;
        }
        
        public Quadrilateral(string _name_, T _base_, T _height_)
        {
            name   = _name_;
            basis  = _base_;
            height = _height_;
        }
        
        public string Describe()
        {
            return "A quadrilateral is a geometric figure with four sides";
        }
        
        public string ShowCharacteristics()
        {
            return $"Geometric Figure: {name}. Description: {Describe()}. Base: {basis}, Height: {height}";
        }
    }
}

You can then use the class by declaring a variable of it. Here are examples:

@page
@model Valuable.Pages.GenericsModel
@{
    // Trapezoid with equal sides
    var kite = new Quadrilateral<double>("Beach Kite", 18.64, 18.64);
            
    // Rectangle, in meters
    var basketballStadium = new Quadrilateral<int>();
    
    basketballStadium.name   = "Basketball Stadium";
    basketballStadium.basis  = 15;
    basketballStadium.height = 28;
}

@functions{
    public class Quadrilateral<T>
    {
        public T basis;
        public T height;
        public string name;
        
        public Quadrilateral(string _name_ = "Quadrilateral")
        {
            name = _name_;
        }
        
        public Quadrilateral(T _base_, T _height_)
        {
            name = "Quadrilateral";
            basis = _base_;
            height = _height_;
        }
        
        public Quadrilateral(string _name_, T _base_, T _height_)
        {
            name   = _name_;
            basis  = _base_;
            height = _height_;
        }
        
        public string Describe()
        {
            return "A quadrilateral is a geometric figure with four sides";
        }
        
        public string ShowCharacteristics()
        {
            return $"Geometric Figure: {name}. Description: {Describe()}. Base: {basis}, Height: {height}";
        }
    }
}

<h3>Geometry: Quadrilaterals</h3>

<p>----------------------------------------------------</p>

<p>@kite.ShowCharacteristics()</p>

<p>@basketballStadium.ShowCharacteristics()</p>

<p>=================================</p>

This would produce:

Geometry: Quadrilaterals
--------------------------------
Geometric Figure: Beach Kite, Description: A quadrilateral is a geometric figure with four sides, Base: 18.64, Height: 18.64
Geometric Figure: Basketball Stadium, Description: A quadrilateral is a geometric figure with four sides, Base: 15, Height: 28
=================================

Deriving from a Generic Class

If you have a generic class that can serve as a foundation for another class, you can derive a class from the generic one. To do this, use the formula we apply when deriving a class but follow the name of each class with <>. Inside the <> operator, enter the same identifier to indicate that the class is a generic type that is based on another generic class. Here is an example:

@functions{
    public class Square<T> : Quadrilateral<T>
    {
    }
}

In the body of the new class, you can use the parameter type. For example, you can declare some member variables of that type. You can create methods that return the parameter type or you can pass arguments of the parameter type. When implementing the methods of the new class, use the member variables of the parameter and the argument(s) based on the parameter type. You can then declare a variable of the class and use it as we have done so far for other generic classes. Here is an example:

@functions{
    public class Quadrilateral<T>
    {
        public T basis;
        public T height;
        public string name;
        
        public Quadrilateral(string _name_ = "Quadrilateral")
        {
            name = _name_;
        }
        
        public Quadrilateral(T _base_, T _height_)
        {
            name = "Quadrilateral";
            basis = _base_;
            height = _height_;
        }
        
        public Quadrilateral(string _name_, T _base_, T _height_)
        {
            name   = _name_;
            basis  = _base_;
            height = _height_;
        }
        
        public string Describe()
        {
            return "A quadrilateral is a geometric figure with four sides";
        }
        
        public string ShowCharacteristics()
        {
            return $"Geometric Figure: {name}. Description: {Describe()}. Base: {basis}, Height: {height}";
        }
    }

    public class Square<T> : Quadrilateral<T>
    {
        public Square()
        {
            name = "Square";
        }
        
        public Square(string _name_)
        {
            name = "Square";
        }
        
        public Square(T side)
        {
            name   = "Square";
            basis  = side;
            height = side;
        }
        
        public Square(string _name_, T _side_)
        {
            name   = _name_;
            basis  = _side_;
            height = _side_;
        }

        public string Describe()
        {
            return "A square is a quadrilateral with four equal sides";
        }
        
        public string ShowCharacteristics()
        {
            return $"Geometric Figure: {name}. Description: {Describe()}. {Describe()}. Side: {basis}";
        }    
    }
}

You can then use the class. Here is an example:

@page
@model Valuable.Pages.GenericsModel
@{
    var plate = new Square<Byte>();
    
    plate.name   = "Plate";
    plate.basis  = 15;
    plate.height = 28;
}

@functions{
    public class Quadrilateral<T>
    {
        public T basis;
        public T height;
        public string name;
        
        public Quadrilateral(string _name_ = "Quadrilateral")
        {
            name = _name_;
        }
        
        public Quadrilateral(T _base_, T _height_)
        {
            name   = "Quadrilateral";
            basis  = _base_;
            height = _height_;
        }
        
        public Quadrilateral(string _name_, T _base_, T _height_)
        {
            name   = _name_;
            basis  = _base_;
            height = _height_;
        }
        
        public string Describe()
        {
            return "A quadrilateral is a geometric figure with four sides";
        }
        
        public string ShowCharacteristics()
        {
            return $"Geometric Figure: {name}. Description: {Describe()}. Base: {basis}, Height: {height}";
        }
    }

    public class Square<T> : Quadrilateral<T>
    {
        public Square()
        {
            name = "Square";
        }
        
        public Square(string _name_)
        {
            name = "Square";
        }
        
        public Square(T side)
        {
            name   = "Square";
            basis  = side;
            height = side;
        }
        
        public Square(string _name_, T _side_)
        {
            name   = _name_;
            basis  = _side_;
            height = _side_;
        }
        public string Describe()
        {
            return "A square is a quadrilateral with four equal sides";
        }
        
        public string ShowCharacteristics()
        {
            return $"Geometric Figure: {name}. Description: {Describe()}. {Describe()}. Side: {basis}";
        }    
    }
}

<pre>Geometry: Quadrilaterals
--------------------------------
@plate.ShowCharacteristics()
=================================</pre>

This would produce:

Geometry: Quadrilaterals
--------------------------------
Geometric Figure: Plate. Description: A square is a quadrilateral with four equal sides. A square is a quadrilateral with four equal sides. Side: 15
=================================

A Generic Interface

Introduction

If you are planning to create many generic classes, you can start or provide their common characteristics or behaviors in an interface.

Creating a Generic Interface

To create a generic interface, you primarily follow the rules for creating an interface except that you must add a parameter type. Here is an example:

@functions{
    public interface ICounter<T>
    {
    }
}

You should also add a (the) member(s) that the implementers will have to override. Here are examples of two members:

@functions{
    public interface ICounter<T>
    {
        T Get(int index);
    }
}

In the same way, you can derive a generic interface from another generic interface. Here is an example:

@functions{
    public interface ICounter<T>
    {
        T Get(int index);
    }

    public interface IBuilder<T> : ICounter<T>
    {
        void Add(T item);
    }
}

Implementing a Generic Interface

After creating a generic interface, when deriving a class from it, follow the formula we reviewed for inheriting from a generic class. This means that the deriving class must use (a) parameter type(s). Here is an example:

@functions{
    public interface ICounter<T>
    {
        T Get(int index);
    }

    public interface IBuilder<T> : ICounter<T>
    {
        void Add(T item);
    }

    public class People<T> : IPersons<T>
    {
    }
}

When implementing the derived class, you must observe all rules that apply to interface implementation. That is, you must implement all the members of the generic interface. Of course, you can also add new members if you want. After implementing the interface, you can declare a variable of the class and use it as you see fit. To do this, after the name of the class, make sure you specify the parameter type between < and >. Initialize the variable appropriately. After that, you can acccess the members of the class.

Remember that you can declare the variable using either the var or the dynamic keyword.

A Generic Interface as Parameter

A generic interface is primarily a normal interface like any other. It can be used to declare a variable but assigned the appropriate class.

In the same way, a generic interface can be returned from a method. Here is an example:

@functions{
    public interface ICounter<T>
    {
        T Get(int index);
    }

    public interface IBuilder<T> : ICounter<T>
    {
        void Add(T item);
    }

    public class Associate<T> : IBuilder<T>
    {
        public void Add(T pers)
        {

        }

        public T Get(int index)
        {
            // . . .;
        }
    }

    public class College
    {
        public IBuilder<Course> CreateCourses()
        {
            Associate<Course> courses = new Associate<Course>();
            
            Course crs = new Course();
            crs.CourseName = "Online Research";
            crs.Credits = 1;
            courses.Add(crs);
            
            crs = new Course() { CourseName = "General Chemistry", Credits = 3 };
            courses.Add(crs);
            courses.Add(new Course() { CourseName = "Workplace Learning in Biology", Credits = 6 });
            courses.Add(new Course() { CourseName = "Linear Geometry 1", Credits = 4 });
            
            return courses;
        }
    }
    
    public class Course
    {
        public string CourseName { get; set; }
        public int Credits { get; set; }
    }
}

Here is an example of getting the returned generic value:

@{
    College university = new College();
    IBuilder<Course> studies = university.CreateCourses();
}

A generic interface can also be passed as argument. You pass a generic interface primarily the same way you would a regular interface. In the body of the method, you can ignore the argument or use it any way appropriate. Here is an example:

@functions{
    public interface ICounter<T>
    {
        T Get(int index);
    }

    public interface IBuilder<T> : ICounter<T>
    {
        void Add(T item);
    }

    public class Associate<T> : IBuilder<T>
    {
        public void Add(T pers)
        {

        }

        public T Get(int index)
        {
            return . . .;
        }
    }
    
    public class College
    {
        public IBuilder<Course> CreateCourses()
        {
            Associate<Course> courses = new Associate<Course>();
            
            Course crs = new Course();
            crs.CourseName = "Online Research";
            crs.Credits = 1;
            courses.Add(crs);
            
            crs = new Course() { CourseName = "General Chemistry", Credits = 3 };
            courses.Add(crs);
            courses.Add(new Course() { CourseName = "Workplace Learning in Biology", Credits = 6 });
            courses.Add(new Course() { CourseName = "Linear Geometry 1", Credits = 4 });
            
            return courses;
        }
        
        public string Show(IBuilder<Course> values)
        {
            string strCourses = "";
            
            . . .

            return strCourses;
    }
}

Here is an example of passing the generic object as argument:

@model Valuable.Pages.GenericsModel
@{
    College university = new College();
    IBuilder<Course> studies = new Associate<Course>();
            
    studies.Add(new Course() { CourseName = "Business Startup", Credits = 1 });
    studies.Add(new Course() { CourseName = "Introduction to Business and Management", Credits = 3 });
    studies.Add(new Course() { CourseName = "Fundamentals of Digital Media", Credits = 3 });
    studies.Add(new Course() { CourseName = "Predictive Modeling", Credits = 6 });
    studies.Add(new Course() { CourseName = "Financial Management for Health Care Organizations", Credits = 3 });
    
    string summary = university.Show(studies);
}

@functions{
    public interface ICounter<T>
    {
        T Get(int index);
    }

    public interface IBuilder<T> : ICounter<T>
    {
        void Add(T item);
    }

    public class Associate<T> : IBuilder<T>
    {
        public void Add(T pers)
        {

        }

        public T Get(int index)
        {
            return . . .;
        }
    }
    
    public class College
    {
        public IBuilder<Course> CreateCourses()
        {
            Associate<Course> courses = new Associate<Course>();
            
            Course crs = new Course();
            crs.CourseName = "Online Research";
            crs.Credits = 1;
            courses.Add(crs);
            
            crs = new Course() { CourseName = "General Chemistry", Credits = 3 };
            courses.Add(crs);
            courses.Add(new Course() { CourseName = "Workplace Learning in Biology", Credits = 6 });
            courses.Add(new Course() { CourseName = "Linear Geometry 1", Credits = 4 });
            
            return courses;
        }
        
        public string Show(IBuilder<Course> values)
        {
            string strCourses = "";
            
            . . .
            
            return strCourses;
        }
    }
    
    public class Course
    {
        public string CourseName { get; set; }
        public int Credits { get; set; }
    }
}

A Generic Interface as a Parameter Type

A generic interface can be used as a parameter type. When creating a method, in its <> operator, specify the desired interface.

A generic interface can also be used as the parameter type of an interface. As the number one rule for all methods that return a value, before exiting the method, you must return an object that is compatible with the generic interface. To do this, in the body of the method, you can declare a variable of a class that implements the interface, use that variable any appropriate way you want, and return it. Here is an example:

@functions{
    public interface ICounter<T>
    {
        T Get(int index);
    }

    public interface IBuilder<T> : ICounter<T>
    {
        void Add(T item);
    }

    public interface IGovernment
    {
    }

    public class Country : IGovernment
    {
    }

    public class Associate<T> : IBuilder<T>
    {
        private int size;

        public void Add(T pers)
        {
            
        }
        
        public T Get(int index)
        {
            return . . .;
        }
    }
    
    public class Politics
    {
        public Associate<IGovernment> Create()
        {
            IGovernment gov = new Country();
            
            Associate<IGovernment> country = new Associate<IGovernment>();
            country.Add(gov);
            
            return country;
        }
    }
}

Previous Copyright © 2008-2022, FunctionX Tuesday 19 October 2021 Next