Introduction to Interfaces
Introduction to Interfaces
Introduction
An interface is a structural layout that resembles a class but has the following characteristics:
Practical Learning: Introducing Interfaces
namespace Geometry1.Pages { public class Triangle { } }
The basic formula to create an interface is:
[ access-modifier(s) ] interface name { members }
The access modifiers can be any of those we have seen in previous lessons (public, protected, internal, private, or protected internal). If you omit the access modifier, it is assumed to be public. To create an interface, you use a keyword named interface. This keyword is followed by the name of the interface. By tradition, the name of an interface starts with I. The section between the curly brackets is the body of the interface.
To create an interface, you can use a text editor such as Notepad, include your code, and save the file with .cs extension. If you are using Microsoft Visual Studio, to created an interface, on the main menu, click Project -> Add New Item... In the Add New Item dialog box, select Interface, give it a name and click Add.
Practical Learning: Creating an Interface
namespace Geometry1.Pages
{
public interface IPolygon
{
}
}
Implementing an Interface
After creating an interface, to implement it, as mentioned in our introduction, create a class that derives from the interface.
interface IPolygon
{
}
public class Triangle : IPolygon
{
}
As with other classes, once you have the class, you can create objects from it and instantiate it using the new operator.
Practical Learning: Implementing an Interface
public class EquilateralTriangle : IPolygon
{
}
Interfaces and Objects
Creating an Object from an Interface-Derived Class
After implementing an interface, you can create an object of a class that implements it. Here is an example from the the above class:
void Create()
{
EquilateralTriangle et = new EquilateralTriangle();
}
By using the name of the class to declare a variable, you can access any non-private member of the class.
Declaring a Variable of Interface Type
You cannot declare a variable of an interface and use it directly as you would a regular class. Instead, you can declare a variable by using the name of the interface but not allocate memory for the variable. Here is an example:
void Create() { IPolygon figure; }
When allocating memory for the object using the new operator, you must use a class that implements that interface. Here is an example:
void Create()
{
IPolygon figure;
figure = new EquilateralTriangle();
}
You can also declare the variable and allocate its memory on the same line. Here is an example:
void Create()
{
IPolygon figure = new EquilateralTriangle();
}
After that, you can use the object.
Introduction to the Members of an Interface
As mentioned earlier, the purpose of an interface is to create a skeleton for classes. When creating an interface, in its body, create the necessary members. Unlike classes, the following keywords are not allowed on the members of an interface: private, public, protected, internal, etc.
In the class that is based on the interface, you must implement the members of the interface. This means that you must create a definition for each member of the interface.
Interfaces and Methods/Functions
A Method in an Interface
An interface can contain one or more methods. A method is created without a body. The formula to follow is:
return-type method-name();
Here is an example:
interface IPolygon
{
double CalculatePerimeter();
}
In the same way, you can add as many methods as you want. In every class that implements the interface, you must define each of the interface's methods.
Practical Learning: Adding a Method to an Interface
namespace Geometry1.Pages
{
public interface IPolygon
{
double CalculateInscribedRadius();
double CalculateCircumscribedRradius();
}
}
namespace Geometry1.Pages { public class Triangle : IPolygon { public int SpecifyEdges() { return 3; } public double side; public int SpecifyInternalAngle() { return 60; } public double CalculatePerimeter() { return side * SpecifyEdges(); } public double CalculateArea() { // Not ready to calculate return 0.00; } public double CalculateInscribedRadius() { // Not ready to calculate return 0.00; } public double CalculateCircumscribedRradius() { // Not ready to calculate return 0.00; } } }
An interface cannot contain a constructor. Instead, you can create one or more constructors in a class that implements the interface. From a constructor, you can access any of the members of the interface.
Passing an Interface As Argument
A parameter of a method can be an interface type. In the body of such a method, you can access (only) the members of the interface. When calling the method, pass an object of the interface but that object should have been initialized with a class that implements the interface.
Returning an Interface
A method can return an object of an interface type. When creating the method, specify its return type as the desired interface. In the body of the method, remember that you cannot simply instantiate an interface and directly use it as you would an object of a class. As a result, you cannot directly return an object of an interface type. Instead, you can declare a variable of the desired interface, initialize it with a class that implements the interface and then return that variable.
Interfaces and Inheritance
Inheriting an Interface
An interface can be derived from another interface (but an interface cannot derive from a class). Obviously the derived interface is supposed to add some behavior using members such as methods. Here is an example:
interface IPolygon
{
}
interface IPolyhedron : IPolygon
{
}
As you should know already that nothing is implemented in an interface, a member of the parent interface cannot be defined in a derived interface. Also, any class that needs the behavior(s) of the derived interface must implement all members of the derived interface and those of the parent interface(s). Here is an example:
interface IPolygon
{
}
interface IPolyhedron : IPolygon
{
}
public class Tetrahedron : IPolyhedron
{
public double side;
public double area;
public double volume;
}
In the same way, an interface can inherit from an interface that itself inherits from another interface, and from another, and so on.
Implementing Many Interfaces
In a C# program, you cannot create a class that inherits from many classes at the same time (there are other languages that support creating a class deriving from many classes). Instead, you can create a class that implements more than one interface. To create a class based on more than one interface, after the colon applied to the class, enter the name of each interface and separate them with commas. Here is an example:
interface IPolygon
{
}
interface IColorizer
{
}
public class Triangle : IPolygon, IColorizer
{
}
In the above example, we created a class that implements only two interfaces. You can create a class that implements as many interfaces as you want. Also, the same interface can be implemented differently in different classes.
Introduction to Built-In Interfaces
Overview
The .NET library provides a large collection of interfaces that you can implement in your classes. Many of the classes available in the .NET library implement these interfaces. In some of your projects, you may have to implement one or more of the existing interfaces for your class.
Practical Learning: Introducing Built-In Interfaces
The collection of techniques and formulas used by a language to display its values is referred to as a format provider. When you use a variable that uses a particular formula to display its value, to help you specify the right formula, the .NET library provides an interface named IFormatProvider. IFormatProvider is defined in the System namespace.
There are two main ways you can use the IFormatProvider interface. You can create a class and implement it. The IFormatProvider interface is equipped with only one method: GetFormat.
In most cases, you will use classes that already implement the IFormatProvider interface. Those classes are equipped with a method named ToString. That method uses a parameter of type IFormatProvider. Its syntax is:
public string ToString(IFormatProvider provider)
This method requires that you create an IFormatProvider object and pass it as argument. An alternative is to pass a string. This is possible with another version of the ToString() method whose syntax is:
public string ToString(string format)
This method takes a string as argument. The string can take a letter as one of the following:
Letter | Description | |
c | C | Currency values |
d | D | Decimal numbers |
e | E | Scientific numeric display such as 1.45e5 |
f | F | Fixed decimal numbers |
d | D | General and most common type of numbers |
n | N | Natural numbers |
r | R | Roundtrip formatting |
x | X | Hexadecimal formatting |
p | P | Percentages |
Practical Learning: Formatting Some Values
@page @model Valuable.Pages.FormattingValuesModel @{ int natural = 13972418; double fractional = 13972418.65; Console.WriteLine("============================================="); Console.WriteLine("Decimal Number Fixed: {0}", fractional.ToString("f")); Console.WriteLine("---------------------------------------------"); Console.WriteLine("Natural Number Decimal: {0}", natural.ToString("D")); Console.WriteLine("---------------------------------------------"); Console.WriteLine("Natural Number Currency: {0}", natural.ToString("c")); Console.WriteLine("---------------------------------------------"); Console.WriteLine("Decimal Number Currency: {0}", fractional.ToString("c")); Console.WriteLine("---------------------------------------------"); Console.WriteLine("Decimal Number Scientific: {0}", natural.ToString("e")); Console.WriteLine("---------------------------------------------"); Console.WriteLine("Natural Number Scientific: {0}", fractional.ToString("e")); Console.WriteLine("---------------------------------------------"); Console.WriteLine("Decimal Number Natural: {0}", fractional.ToString("n")); Console.WriteLine("---------------------------------------------"); Console.WriteLine("Natural Number Natural: {0}", natural.ToString("n")); Console.WriteLine("---------------------------------------------"); Console.WriteLine("Decimal Number Natural: {0}", fractional.ToString("n")); Console.WriteLine("---------------------------------------------"); Console.WriteLine("Natural Number Natural: {0}", natural.ToString("n")); Console.WriteLine("---------------------------------------------"); Console.WriteLine("Decimal Number General: {0}", fractional.ToString("g")); Console.WriteLine("---------------------------------------------"); Console.WriteLine("Natural Number Hexadecimal: {0}", natural.ToString("x")); Console.WriteLine("============================================="); } <hr /> <pre>Decimal Number Fixed: @fractional.ToString("f") --------------------------------------------- Natural Number Decimal: @natural.ToString("D") --------------------------------------------- Natural Number Currency: @natural.ToString("c") --------------------------------------------- Decimal Number Currency: @fractional.ToString("c") --------------------------------------------- Decimal Number Scientific: @natural.ToString("e") --------------------------------------------- Natural Number Scientific: @fractional.ToString("e") --------------------------------------------- Decimal Number Natural: @fractional.ToString("n") --------------------------------------------- Natural Number Natural: @natural.ToString("n") --------------------------------------------- Decimal Number Natural: @fractional.ToString("n") --------------------------------------------- Natural Number Natural: @natural.ToString("n") --------------------------------------------- Decimal Number General: @fractional.ToString("g") --------------------------------------------- Natural Number Hexadecimal: @natural.ToString("x")</pre> <hr />
Decimal Number Fixed: 13972418.65 --------------------------------------------- Natural Number Decimal: 13972418 --------------------------------------------- Natural Number Currency: $13,972,418.00 --------------------------------------------- Decimal Number Currency: $13,972,418.65 --------------------------------------------- Decimal Number Scientific: 1.397242e+007 --------------------------------------------- Natural Number Scientific: 1.397242e+007 --------------------------------------------- Decimal Number Natural: 13,972,418.65 --------------------------------------------- Natural Number Natural: 13,972,418.00 --------------------------------------------- Decimal Number Natural: 13,972,418.65 --------------------------------------------- Natural Number Natural: 13,972,418.00 --------------------------------------------- Decimal Number General: 13972418.65 --------------------------------------------- Natural Number Hexadecimal: d533c2
Cloning an Object
Consider a class as follows:
@functions{ public class Circle { public Circle() { radius = 0.00; } public Circle(double rad) { radius = rad; } public double radius; public double CalculateArea() { return radius * radius * 3.14156; } public double CalculateDiameter() { return radius * 2; } } }
Copying an object consists of creating another sample of it and that contains the same values as the original. To make this operation available to your classes, the .NET library provides an interface named ICloneable. When necessary, you can implement that interface for your class. The ICloneable interface is defined in the System namespace of the mscorlib.dll library.
The ICloneable interface is equipped with one method named Clone. Its syntax is:
object Clone();
To assist you with making a copy of a variable, the Object class is equipped with a method named MemberwiseClone. This means that all classes of the .NET library and any class you create in a C# application automatically inherits this method. The syntax of this method is:
protected Object MemberwiseClone();
When implementing the ICloneable interface, in your class, you can simply call the MemberwiseClone() method. Here is an example:
@functions{ public class Circle { public double radius; public Circle() { radius = 0.00; } public Circle(double rad) { radius = rad; } public double CalculateArea() { return radius * radius * 3.14156; } public double CalculateDiameter() { return radius * 2; } } public class Cylinder : Circle, ICloneable { public double height; public Cylinder(double baseRadius, double hgt) { radius = baseRadius; height = hgt; } public double CalculateVolume() { return CalculateArea() * height; } public object Clone() { return MemberwiseClone(); } } }
Comparing Two Objects
Comparing two objects consists of finding out which one comes first, for whatever criterion (or criteria, plural) you want to consider. The comparison is simple if you are dealing with values of primitive types. For example, it is easy to know that 2 is lower than 5, but it is not obvious to compare two objects created from a composite type, such as two students, two cars, or two food items. Consider the following Student class:
@functions{ public class Student { public int studentNumber; public string firstName; public string lastName; public double age; public Student(int number = 0, string first = "John", string last = "Doe", double ag = 1) { studentNumber = number; firstName = first; lastName = last; age = ag; } } }
To assist you with comparing two objects, the .NET Framework provides various comparable interfaces. One of these interfaces is named IComparable. The IComparable interface is a member of the System namespace. Obviously you must define what would be compared and how the comparison would be carried. For example, to compare two Student objects of the above class, you can ask the compiler to base the comparison on the student number. Here is an example:
@functions{ public class Student : IComparable { public int studentNumber; public string firstName; public string lastName; public double age; public Student(int number = 0, string first = "John", string last = "Doe", double ag = 1) { studentNumber = number; firstName = first; lastName = last; age = ag; } public int CompareTo(object obj) { Student std = (Student)obj; return std.studentNumber.CompareTo(studentNumber); } } }
Here is an example of comparing two Student objects:
@page @model Valuable.Pages.FormattingValuesModel @{ Student std1 = new Student(294759, "Patricia", "Katts", 14.50); Student std2 = new Student(294706, "Raymond", "Kouma", 18.50); Student std3 = new Student(747747, "Patricia", "Childs", 12.00); } @functions{ public class Student : IComparable { public int studentNumber; public string firstName; public string lastName; public double age; public Student(int number = 0, string first = "John", string last = "Doe", double ag = 1) { studentNumber = number; firstName = first; lastName = last; age = ag; } public int CompareTo(object obj) { Student std = (Student)obj; return std.studentNumber.CompareTo(studentNumber); } } } <pre>Red Oak High School ----------------------- Comparison by Student Number First = Second: @std1.CompareTo(std2) First = Third: @std1.CompareTo(std3) =============================</pre>
This would produce:
Red Oak High School ----------------------- Comparison by Student Number First = Second: -1 First = Third: 1 =============================
In the same way, you can choose any other member of the class to base the comparison. An example would consist of comparing the last names of students.
Most of the .NET library classes that need to perform comparison already implement the IComparable interface or one of its equivalents.
Disposing of an Object
Introduction
Most objects that are used in an application consume memory and other resources. Some objects use more resources than others. Whenever you have finished using an object, you should (mostly must) make sure you free the resources it was using. In traditional programming, you would add a destructor to your class. Then, in the destructor, you would call the method(s) from which your objects consume resources. Here is an example:
@functions{ public class Book { public int numberOfPages; public void Read() { } } public class Student { public Book text; public Student() { text = new Book(); } public void ReleaseTheResources() { } ~Student() { ReleaseTheResources(); } } }
To assist you in dismissing the resources used in your application, the .NET libray provides an interface named IDisposable. Most of the time, you will not need to implement this interface because most of the classes that are resource-intensive have already been created and you will just use them. Those classes directly or indirectly implement the IDisposable interface. Here is an example of a class that already implement the IDisposable interface:
public class ScrollableControl : Control, IComponent, IDisposable { }
There are two main ways you will use the IDisposable interface. One way is that, if you have to, that is, if you judge it necessary, you can create a class that implements the IDisposable interface. The IDisposable interface is defined in the System namespace that is a member of the mscorlib.dll library. This means that you don't have to import any library to use it. The IDisposable interface contains only one method, named Dispose. Its syntax is:
void Dispose();
When implementing the interface, use this method to free the resources a variable of the class was using. After calling this method, remember that the destructor of a class is always called when the variable gets out of scope. For this reason, it is a good idea to create a destructor for the class and call the Dispose() method from it. Here is an example:
@functions{ public class Book { public int numberOfPages; public void Read() { } } public class Student : IDisposable { public Book text; public Student() { text = new Book(); } public void Dispose() { } ~Student() { Dispose(); } } }
Using and Disposing of an Object
The second way you can use the IDisposable interface is the most important for us. To support the ability to release the resources that an object was using, the C# language provides an operator named using. The formula to use it is:
using(parameter) { }
As you can see, this operator uses the formula of a method (or function). It must be equipped with parentheses and a body delimited by curly brackets. In the parentheses, declare the variable that will use the resources you are concerned with. Inside the brackets, use the variable anyway you want and that is appropriate. When the compiler reaches the closing curly bracket, it does what is necessary. For example, the compiler may have to close a connection that was used or it would delete the object that was consuming the resources. Here is an example of using using:
@functions{ public class Book { public int numberOfPages; public void Read() { } } public class Student : IDisposable { public Book text; public Student() { text = new Book(); } public void Buy() { } public void Dispose() { } ~Student() { Dispose(); } } public class Exercise { public void View() { using (Student std = new Student()) { std.Buy(); } } } }
Introduction to HTML Helpers
Overview
We have seen that you can create a Web for using HMTL tags. To support Web forms, the .NET library provides its own objects. These objects allow you to create tags but using C# code. The .NET objects used to create tags on a webpage are referred to as HTML helpers.
To support Web controls that are added to a Web form , the .NET library is equipped with an interface named IHtmlHelper. This interface is equipped with various methods for any Web control you want to add to a form.
Adding a Text Box to a Web Form
To let you add a text box to a Web form, the IHtmlHelper interface is equipped with a method named TextBox. The method comes in various versions. One of the versions of this method uses the following syntax:
public Microsoft.AspNetCore.Html.IHtmlContent TextBox(string expression, object value, object htmlAttributes);
This version of the method takes three arguments. The first argument is the C# name of the control. It is practically like the name of a variable. The second argument is the value that the text box should display. In previous lessons, we saw that, to display a value in a webpage, you could declare a variable in an @{} section. Then, in the HTML code, you use that variable but precede it with the @ symbol. That rule is the same you can apply to the second argument of the IHtmlHelper.TextBox() method. The third argument of the IHtmlHelper.TextBox() method is of type object. This means that the third argument can be almost anything. If you don't have a value for it, you can pass the third argument as null. By tradition, the third argumenti used to format the text box with CSS code. To do that, pass the third argument as new { . . . }. In the curly bracket, specify the CSS format you want. If you want to create a local format, assign its string to a style object (we will see examples).
Adding a Label to a Form
To let you create a label on a form, the IHtmlHelper interface provides a method named Label. Its syntax is as follows:
public Microsoft.AspNetCore.Html.IHtmlContent Label (string expression, string labelText, object htmlAttributes);
This method takes three arguments. The first argument is the name of the label. It is the same as a name of a variable. The second argument is the text that the label should display to the user. The third argument allows you to create HTML code to apply to the label. You can use that argument to indicate the Web control (text box, combo box, text area, etc) to which the label is associated. The same thid control allows you to create CSS formatting to apply to the label.
Practical Learning: Ending the Lesson
|
|||
Previous | Copyright © 2003-2022, FunctionX | Friday 14 January 2022 | Next |
|