Class interfaces play a key role with inheritance

Class interfaces in C# ensure that your code will behave the way you expect. In this installment of C# for Newbies, Harold Davis outlines the role of class interfaces in inheritance and abstract base classes.

A class interface is like a kind of contract. If a class implements an interface, it means that it—and any derived classes that inherit from the initial class—must have implementations for the members whose signatures are included in the implementation specification. So if you know that a class implements an interface, you know that it implements certain members, and you know what to expect about how those members work—at least in terms of method signatures and member type. (There is, of course, nothing to stop someone from implementing a method specified by an interface as a stub. A method written this way meets the contract specified by the interface, but it doesn’t actually do anything.)

In the first part of this article, we’ll take a closer look at class interfaces. We'll consider how they compare with abstract base classes and when they should be used. Next, we'll discuss some of the most important .NET interfaces. Finally, we'll look at how to create a class that implements the IComparable interface. (As you'll see, implementing IComparable means that the class must contain a comparison method for ordering objects based on the class.) Future articles will focus on creating custom interfaces.

Understanding class interfaces
By convention, interfaces are named starting with a capital I, with the subsequent letter also capitalized. (Another example besides IComparable is IEnumerable.) An interface is like an abstract base class: Neither spells out implementation details and both are used by derived classes. However, a class can derive from a base class and can also implement an interface—or, in fact, implement multiple interfaces. (In contrast, C# classes can inherit only from one base class.) In this respect, interfaces are more general—and arguably more useful—than class inheritance.

Interface implementations help ensure consistency. Studies have shown that software written with class libraries that implement interfaces tends to have fewer defects.

Interfaces work well in situations in which one set of programmers has created a class library (for example, the creators of the .NET Framework) and another set will be using the classes (you and me). Interface implementation also provides a good way for a team leader to deliver project specifications: The project lead writes the interfaces and specifies mandatory implementation within classes.

As I’ll show you later in this article, the Visual Studio .NET development environment itself helps to enforce the contract created by an interface. If you attempt to run a project containing a class that implements an interface, and the members specified by the interface are not implemented in the class, you’ll get syntax errors and the project containing the code will neither run nor compile.

Using the Object Browser
As is the case with much of the .NET Framework, the Object Browser is one of the best ways to perform discovery about .NET interfaces. (You can open the Object Browser by selecting Other Windows from the Visual Studio View menu and choosing Object Browser or by pressing [Ctrl][Alt]J.)

The Object Browser tells you what interfaces a given class implements and provides a summary description of each interface. Furthermore, if you highlight an interface, the Members pane of the Object Browser will show you the members that the interface specifies. In Figure A, the Object Browser is showing the CompareTo method specified by the IComparable interface implemented by the String type.

Figure A

Important .NET interfaces
Many notable class interfaces are part of the .NET Framework. Here are some important ones:
  • ·        ICloneable: Supports cloning, which creates a new instance of a class with the same value as an existing instance of the class.
  • ·        ICollection: Defines size, enumerators, and synchronization methods for all collections.
  • ·        IComparable: Specifies that the class provides a CompareTo method allowing comparison between a current instance of the class and another object of the same type.
  • ·        IEnumerable: Allows iteration using an enumerator over a collection.
  • ·        IFormattable: Provides functionality to format an object into a string.
  • ·        IHttpHandler: Defines the contract that ASP.NET implements to synchronously process HTTP Web requests using custom HTTP handlers.
  • ·        IHttpModule: Provides ASP.NET module initialization and disposal events to the implementing class.

Implementing IComparable
It’s time to get started with some classes that demonstrate implementing interfaces. For this demonstration, I’ll implement IComparable, which allows an ordered sort of objects of the same type that implement the interface. The example uses a base Dinosaur class, and specialized dinosaur classes—Allosaurus, TRex, etc.—derived from the base Dinosaur class. This is not particularly functional in the real world (after all, the dinosaurs are extinct). But it should show you how to implement an interface.

Listing A provides the base Dinosaur class without specifying any interfaces to implement.

As you can see, the Dinosaur class is a pretty simple affair, consisting of a public property (Name) and a Length field.

Next, let’s add some specific dinosaur classes that derive from Dinosaur via inheritance, as shown in Listing B.

You can now go back to the Dinosaur class and implement the IComparable interface using the same colon operator (:) used for inheritance:
public class Dinosaur : IComparable

By implementing the IComparable interface in the Dinosaur class, it will also, of course, be implemented in all derived classes, such as Allosaurus and TRex. Listing C shows this implementation of Dinosaur class.

As the code stands, IComparable is specified in the inheritance clause of the Dinosaur class, but there is no actual implementation in Dinosaur or its derived classes of the members specified in the IComparable “contract.” If you attempt to compile it, the project will not run, and you’ll get a syntax error pinpointing the problem, as shown in Figure B.

Figure B

To actually implement the IComparable interface, the class needs to include a CompareTo method, as shown in Listing D.

Depending on how you look at things, this CompareTo method can be considered a pretty trivial implementation of IComparable—or else cheating. All it does is cast the passed object to type Dinosaur and then take advantage of the ordinary String object’s implementation to perform a comparison based on the Name property of the Dinosaur class. In other words, it just sorts by the name of the class instance.

To see what implementing IComparable allows you to do, suppose you have an array of Dinosaur objects:
jPark = new Dinosaur [4];
jPark[0] = new Lessaemsaurus("lessaemsaurus", 7);
jPark[1] = new Allosaurus("allosaurus", 12);
jPark[2] = new TRex("tRex", 14);
jPark[3] = new Diplodocus("doc", 9);

The Sort method of the System.Array object will then order the Dinosaur objects (since they implement IComparable):
Array.Sort (jPark);

You can see this when you display the array in a ListBox (named lstDino) (see Figure C):
foreach (Dinosaur dino in jPark){

Figure C

At this point, you should have a strong grasp of class interfaces. In the next article, I’ll cover how you can build your own custom interfaces.

Harold Davis is the author of Visual Basic .NET Programming and Visual C# .NET Programming, both published by Sybex, as well as many other books about programming.

Editor's Picks