Class Abstraction
Class Abstraction
Foundations of Abstract Classes
Introduction
A class is said to be abstract if its primary role is to serve as parent for other classes. This means that another class must be derived from the abstract class. After that, the abstract class can be used somehow in an application.
Practical Learning: Creating a Class
.container { width: 275px; margin: auto; } .txtContext { width: 80px } .btnFormat { width: 200px; height: 32px; } .left-column { width: 175px; } .centered { text-align: center }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace GasUtilityCompany2.App_Code { public class BillPreparation { public int InvoiceNumber { get; set; } public decimal CounterReadingStart { get; set; } public decimal CounterReadingEnd { get; set; } /*public BillPreparation(int nbr, double start, double end) { InvoiceNumber = nbr; CounterReadingStart = start; CounterReadingEnd = end; }*/ public decimal CCFTotal { get { return CounterReadingEnd - CounterReadingStart; } } public decimal TotalTherms { get { return CCFTotal * 1.0367m; } } public decimal DistributionAdjustment { get { return TotalTherms * 0.13086m; } } public decimal CalculateTransportationCharges() { if (TotalTherms <= 5000) return TotalTherms * 0.016289m; else return TotalTherms * 0.009577m; } public decimal CalculateDeliveryTotal() { decimal first50Therms = 0, over50Therms = 0; if (TotalTherms < 5000) { first50Therms = TotalTherms * 0.05269m; over50Therms = 0; } else { first50Therms = 5000 * 0.5269m; over50Therms = (TotalTherms - 5000) * 0.04995m; } return CalculateTransportationCharges() + DistributionAdjustment + first50Therms + over50Therms; } public decimal EnvironmentalCharges { get { return CalculateDeliveryTotal() * 0.0045m; } } public decimal AmountDue { get { return CalculateDeliveryTotal() + EnvironmentalCharges; } } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace GasUtilityCompany2.App_Code { public class CustomerInvoice { } }
<!DOCTYPE html> <html> <head> <link rel="stylesheet" type="text/css" href="~/Content/Site.css" /> <title>Gas Utility Company - Bill Preparation</title> </head> <body> <div class="container"> <h2 class="centered">Gas Utility Company</h2> <h3 class="centered">Bill Preparation</h3> <hr /> </div> <div class="container"> <form method="post" name="frmBillPreparation"> <table> <tr> <td class="left-column">Invoice #:</td> <td><input type="text" name="txtInvoiceNumber" class="txtContext" value="" /></td> </tr> <tr> <td>Counter Reading Start:</td> <td><input type="text" name="txtCounterReadingStart" class="txtContext" value="" /></td> </tr> <tr> <td>Counter Reading End:</td> <td><input type="text" name="txtCounterReadingEnd" class="txtContext" value="" /></td> </tr> </table> <p class="centered"><input type="submit" class="btnFormat" value="Prepare Invoice" name="btnPrepareInvoice" /></p> <table> <tr> <td class="left-column">CCF Total:</td> <td><input type="text" name="txtCCFTotal" class="txtContext" value="" /></td> </tr> <tr> <td>Total Therms:</td> <td><input type="text" name="txtTotalTherms" class="txtContext" value="" /></td> </tr> <tr> <td>Ditribution Adjustment:</td> <td><input type="text" name="txtDitributionAdjustment" class="txtContext" value="" /></td> </tr> <tr> <td>Transportation Charges:</td> <td><input type="text" name="txtTransportationCharges" class="txtContext" value="" /></td> </tr> </table> <hr /> <table> <tr> <td class="left-column">Total Delivery:</td> <td><input type="text" name="txtTotalDelivery" class="txtContext" value="" /></td> </tr> <tr> <td>Environment Charges:</td> <td><input type="text" name="txtEnvironmentCharges" class="txtContext" value="" /></td> </tr> </table> <hr /> <table> <tr> <td class="left-column">Amount Due:</td> <td><input type="text" name="txtAmount Due" class="txtContext" value="" /></td> </tr> </table> </form> </div> </body> </html>
Creating an Abstract Class
To let you create an abstract class, the C# language provides a keyword named abstract. Therefore, to create an abstract class, type this keyword to the left of the class keyword. Here is an example:
abstract class Triangle
{
}
If you decide to apply an access level (public or internal) on the class creation, the abstract keyword can appear before or after the access level.
In the class, you can add any type of member, like any of the types of constructors, methods or properties we have used so far.
Practical Learning: Creating an Abstract Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace GasUtilityCompany2.App_Code
{
public abstract class GasUtility
{
. . . No Change
}
}
. . . No Change
<title>Gas Utility Company - Bill Preparation</title>
</head>
<body>
<div class="container">
<h2 class="centered">Gas Utility Company</h2>
<h3 class="centered">Bill Preparation</h3>
<hr />
</div>
@{
GasUtilityCompany2.App_Code.BillPreparation gu = new GasUtilityCompany2.App_Code.BillPreparation();
}
. . . No Change
</body>
</html>
Notice that the constructor is underlined because of an error. If you execute, you would receive an errorDeriving from an Abstract Class
An abstract class cannot be directly used like any of the classes we have used so far. This means that you cannot use a constructor of an abstract class to instantiate an object. You have various solutions to solve this problem. The first thing you must do is to create a class derived from the abstract class. You can then create an object of that class.
Practical Learning: Deriving from an Abstract Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace GasUtilityCompany2.App_Code
{
public class CustomerInvoice : BillPreparation
{
}
}
An Object of an Abstract Class
Although you must always derive a class from an abstract class in order to make the abstract class useful, you can declare a variable of an abstract class. Such a variable must be initialized with a constructor of a class derived from the abstract class.
Practical Learning: Deriving from an Abstract Class
<!DOCTYPE html> <html> <head> <link rel="stylesheet" type="text/css" href="~/Content/Site.css" /> <title>Gas Utility Company - Bill Preparation</title> </head> <body> <div class="container"> <h2 class="centered">Gas Utility Company</h2> <h3 class="centered">Bill Preparation</h3> <hr /> </div> @{ int invoiceNumber = 0; decimal readingEnd = 0; decimal readingStart = 0; GasUtilityCompany2.App_Code.BillPreparation gu = new GasUtilityCompany2.App_Code.CustomerInvoice(); if (IsPost) { gu.InvoiceNumber = invoiceNumber = Request["txtInvoiceNumber"].AsInt(); gu.CounterReadingStart = readingStart = Request["txtCounterReadingStart"].AsDecimal(); gu.CounterReadingEnd = readingEnd = Request["txtCounterReadingEnd"].AsDecimal(); } } <div class="container"> <form method="post" name="frmBillPreparation"> <table> <tr> <td class="left-column">Invoice #:</td> <td><input type="text" name="txtInvoiceNumber" class="txtContext" value=@invoiceNumber /></td> </tr> <tr> <td>Counter Reading Start:</td> <td><input type="text" name="txtCounterReadingStart" class="txtContext" value=@readingStart /></td> </tr> <tr> <td>Counter Reading End:</td> <td><input type="text" name="txtCounterReadingEnd" class="txtContext" value=@readingEnd /></td> </tr> </table> <p class="centered"><input type="submit" class="btnFormat" value="Prepare Invoice" name="btnPrepareInvoice" /></p> <table> <tr> <td class="left-column">CCF Total:</td> <td><input type="text" name="txtCCFTotal" class="txtContext" value=@gu.CCFTotal.ToString("F") /></td> </tr> <tr> <td>Total Therms:</td> <td><input type="text" name="txtTotalTherms" class="txtContext" value=@gu.TotalTherms.ToString("F") /></td> </tr> <tr> <td>Ditribution Adjustment:</td> <td><input type="text" name="txtDitributionAdjustment" class="txtContext" value=@gu.DistributionAdjustment.ToString("F") /></td> </tr> <tr> <td>Transportation Charges:</td> <td><input type="text" name="txtTransportationCharges" class="txtContext" value=@gu.CalculateTransportationCharges().ToString("F") /></td> </tr> </table> <hr /> <table> <tr> <td class="left-column">Total Delivery:</td> <td><input type="text" name="txtTotalDelivery" class="txtContext" value=@gu.CalculateDeliveryTotal().ToString("F") /></td> </tr> <tr> <td>Environment Charges:</td> <td><input type="text" name="txtEnvironmentCharges" class="txtContext" value=@gu.EnvironmentalCharges.ToString("F") /></td> </tr> </table> <hr /> <table> <tr> <td class="left-column">Amount Due:</td> <td><input type="text" name="txtAmount Due" class="txtContext" value=@gu.AmountDue.ToString("F") /></td> </tr> </table> </form> </div> </body> </html>
A Parameter of an Abstract Class
As done for any class, you can create a method that uses a parameter of an abstract class. In the body of the method, use the parameter like any other. For example, you can access the members of the abstract class. Here is an example:
abstract public class Vehicle { public string Make { get; set; } public string Model { get; set; } public int Year { get; set; } } public class Sedan : Vehicle { } public class Presentation { public string Present(Vehicle car) { string strResult = car.Year + " " + car.Make + " " + car.Model; return strResult; } }
When calling a method that uses a parameter of an abstract class, the argument you pass must hold an appropriate value, which should be an object of a class derived from the abstract class. Here is an example:
<!DOCTYPE html> <html> <head> <title>Car Dealer</title> </head> <body> <div> <h4>Car Dealer</h4> @{ Presentation pres = new Presentation(); Sedan m = new Sedan(); m.Make = "Ford"; m.Model = "Focus"; m.Year = 2010; } <p>Presentation: @pres.Present(m)</p> </div> </body> </html>
Returning an Object of Abstract Type
You can create a method that returns an object of an abstract class type. For such a method, make sure it returns an object of that type. Here is an example:
abstract public class Vehicle { public string Make { get; set; } public string Model { get; set; } public int Year { get; set; } } public class Van : Vehicle { } public class Presentation { public Vehicle Create() { Vehicle passenger = new Van(); passenger.Make = "Mercedes-Benz"; passenger.Model = "Sprinter Cargo Van"; passenger.Year = 2017; return passenger; } public string Present(Vehicle car) { string strResult = car.Year + " " + car.Make + " " + car.Model; return strResult; } }
Outside the class, when calling the method, you can assign it to a variable of the abstract class. Here is an example:
<!DOCTYPE html>
<html>
<head>
<title>Car Dealer</title>
</head>
<body>
<div>
<h2>Car Dealer</h2>
@{
Presentation pres = new Presentation();
Vehicle car = pres.Create();
}
<p>Presentation: @pres.Present(car)</p>
</div>
</body>
</html>
Having Many Methods that Return the Same Type of Abstract Object
Consider an abstract class as follows::
public abstract class Triangle { public double Angle1; public double Angle2; public double Side1; }
Imagine you have a method that returns an object of this abstract class. Here is an example:
public abstract class Triangle
{
public double Angle1;
public double Angle2;
public double Side1;
}
public class Oblique : Triangle
{
public Triangle View()
{
Triangle ot = new Oblique();
return ot;
}
}
If you need to have one or more other methods that perform the same type(s) of operation(s) and/or return the same type of object, you don't need to declare a variable to call the first method. Here are examples:
public abstract class Triangle { public double Angle1; public double Angle2; public double Side1; } public class Oblique : Triangle { public Triangle View() { Triangle ot = new Oblique(); return ot; } public Triangle Calculate() { return View(); } public Triangle Evaluate() { return View(); } public Triangle Summarize() { return View(); } }
The Members of an Abstract Class
Introduction
Like a normal class, an abstract class can contain regular and virtual members (methods and properties). As seen for non-abstract classes, if you create a virtual member in an abstract class, an object of the derived class can directly use that member.
Practical Learning: Introducing Abstract Members
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Geometry15.App_Code
{
public abstract class Triangle
{
public double Base { get; set; }
public double Area
{
get
{
return 0.00;
}
}
}
}
Overriding a Virtual Member of an Abstract Class
If you create a virtual member in an abstract class, if you want the derived class to provide a different version of the virtual member, you must override it in the child class. This is done exactly as seen for non-abstract classes.
An Abstract Method
A method is said to be abstract if its class doesn't implement that method but the derived class must implement it. An abstract method can only belong to an abstract class.
To create an abstract method, apply the following rules:
After creating an abstract method, every class that derives from that class must provide an implementation of (each of) the abstract method(s). To implement the method, you must apply the override keyword to it as we reviewed for virtual methods.
Remember that an abstract method must not have a body. If you want the method to have a body, you can mark it with the virtual keyword.
Practical Learning: Creating an Abstract Method
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Geometry15.App_Code
{
public abstract class Triangle
{
public double Base { get; set; }
public double Area
{
get
{
return 0.00;
}
}
public abstract double CalculatePerimeter();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Geometry15.App_Code
{
public class Equilateral : Triangle
{
const double Angle = 60;
public double Side
{
get
{
return Base;
}
}
public override double CalculatePerimeter()
{
return Side * 3.00;
}
}
}
An Abstract Property
A property is abstract if its class doesn't include an implementation of that property. Any class based on the abstract class must implement the abstract property using the override keyword.
If you want to create an abstract property that has only a get accessor, the property must use the abstract keyword. Here is an example:
public abstract class GeometricFigure
{
public abstract double Perimeter { get; }
}
If the property has both a get and a set accessors, it can use either the abstract or the virtual keyword. Here are examples:
public abstract class GeometricFigure { public abstract double Median { get; set; } public virtual double Perimeter { get; set; } }
Practical Learning: Creating an Abstract Property
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Geometry15.App_Code { public abstract class Triangle { public double Base { get; set; } public abstract double Height { get; set; } public double Area { get { return Base * Height / 2.00; } } public abstract double CalculatePerimeter(); } }
using static System.Math; using System.Collections.Generic; using System.Linq; using System.Web; namespace Geometry15.App_Code { public class Equilateral : Triangle { const double Angle = 60; private double hgt; public double Side { get { return Base; } } public override double Height { get { return Sqrt(3.00) * Side / 2.00; } set { hgt = value; } } public override double CalculatePerimeter() { return Side * 3.00; } } }Notice that the error has disappeared
Built-In Abstract Classes: The Type Classes
Introduction
When studying conditional statements, we saw how to check the value held by a variable. In some cases, when you have a variable, you may need to identify the class name of that variable. To assist you with this, the .NET Framework provides an abstract class named Type. The Type class is created in the System namespace. Because Type is an abstract class, you cannot declare a variable of it.
The Type of a Class
To assist you with finding out the data type or the class of a variable, the C# language provides an operator named typeof. Its formula is:
Type type = typeof(DataType | ClassName);
typeof is a unary operator. That is, it acts on one operand. The operand can be a known primitive data type or a class. If you pass a C# data type (such as double, int, or decimal with which we are familiar already) as the operand, the typeof operator produces the equivalent .NET Framework type. In reality, the typeof operator produces the Type name of its operand. Here is an example of using it:
@{
Type tp = typeof(int);
<p>The type of the int is @tp</p>
}
The Type of an Object
You will usually need the services of the Type class to know the data type of a variable or of an argument to a method. To make this possible, the Object class is equipped with a method named GetType. Its syntax is:
public Type GetType();
This method takes no argument and returns the name of the class. Here is an example:
@{
var bp = new GasUtilityCompany2.App_Code.CustomerInvoice();
Type tp = bp.GetType();
}
<p>The bp object is built from the @tp type.</p>
The Type GetType() method can also return the data type of the variable that called it. If the variable that calls this method is of a primitive C# data type, this method returns its .NET Framework equivalent. Here is an example of calling this method:
@{
var number = 22705;
Type tp = number.GetType();
<p>The number variable is of type @tp</p>
}
The Base Type of a Class
The Type.GetType() method gives you the name of the class of a variable. If the class is derived from another class and you want to know the name of its parent class, the Type class can help you, using a property named BaseType. Here is an example of accessing it:
@{ var bp = new GasUtilityCompany2.App_Code.CustomerInvoice(); Type tp = bp.GetType(); } <p>The parent of the CustomerInvoice class is @tp.BaseType</p>
The Assembly a Type Belongs To
If a class is defined in an assembly, you may want to know what that assembly is. To assist you with getting this information, the Type class is equipped with a property named Assembly.
When accessing the Type.Assembly property, make sure the class of the variable you are using has a formal assembly. Otherwise you would receive an error.
The Full Name of a Type
To get the complete name of the class of a variable without the assembly, use the Type.FullName property.
The Namespace of a Type
Besides the assembly in which the class of a variable exists, you may want to know the namespace in which that class is defined. To let you get this information, the Type class is equipped with the Namespace property.
Finding Out Whether a Type is a Class or an Abstract
Sometimes when using a type, you may want to know whether it is a simple regular class, an abstract class, a structure, an enumeration, or another type we haven't studied yet (interface, generic, etc). To assist you with checking this, the Type class provides various Boolean properties such as IsAbstract or IsClass.
Application: Ending the Lesson
|
||
Previous | Copyright © 2002-2019, FunctionX | Next |
|