Learning C# and OOP, Polymorphism and Interfaces, Part 1

Baldwin provides an introduction to interfaces in C#, and compares them with interfaces in Java.

Published:  November 10, 2002
By Richard G. Baldwin

C# Programming Notes # 128a


Preface

This lesson is one of a series of lessons designed to teach you about the essence of Object-Oriented Programming (OOP) using C#.

The first lesson in the group was entitled Learning C# and OOP, Getting Started, Objects and Encapsulation.  That lesson, and each of the lessons following that one, has provided explanations of certain aspects of Object-Oriented Programming using C#.  The previous lesson was entitled Learning C# and OOP, Polymorphism and the Object Class.

Necessary and significant aspects

This miniseries will describe and discuss the necessary and significant aspects of OOP using C#.

If you have a general understanding of computer programming, you should be able to read and understand the lessons in this miniseries, even if you don't have a strong background in the C# programming language.

Viewing tip

You may find it useful to open another copy of this lesson in a separate browser window.  That will make it easier for you to scroll back and forth among the different figures while you are reading about them.

Supplementary material

I recommend that you also study the other lessons in my extensive collection of online programming tutorials.  You will find a consolidated index at www.DickBaldwin.com. 

Preview

What is polymorphism?

The meaning of the word polymorphism is something like one name, many forms.

How does C# implement polymorphism?

Polymorphism manifests itself in C# in the form of multiple methods having the same name.

In some cases, multiple methods have the same name, but different formal argument lists (overloaded methods, which were discussed in a previous lesson).

In other cases, multiple methods have the same name, same return type, and same formal argument list (overridden methods, which were also discussed in a previous lesson).

Three distinct forms of polymorphism

From a practical programming viewpoint, polymorphism manifests itself in three distinct forms in C#:

  • Method overloading
  • Method overriding through inheritance
  • Method overriding through the C# interface

Method overloading

I covered method overloading as one form of polymorphism (compile-time polymorphism) in a previous lesson.  I also explained automatic type conversion and the use of the cast operator for type conversion in a previous lesson.

Method overriding through inheritance

I discussed runtime polymorphism implemented through method overriding and class inheritance in previous lessons.

Method overriding through the C# interface

I will begin a discussion of polymorphism based on method overriding through the C# interface in this lesson.  I will continue with that topic for a few more lessons following this one.

This lesson will provide background information for interfaces in C#.  The next few lessons will provide sample programs that illustrate and expand upon the material contained in this lesson.

For those who are interested, I will also make numerous comparisons between C# interfaces and Java interfaces.  The purpose is to assist those who are making the transition from Java to C#.

Discussion

Interfaces can be difficult to understand

I have been teaching Object-Oriented Programming (OOP) to several hundred Java students each year since 1997. (Prior to that time, I taught OOP using C++.)  During this period, I have found that many students have difficulty understanding polymorphism based on interfaces.

(Note that there are essentially no conceptual differences in the use of interfaces between Java and C#.  Therefore, I would expect students to have the same degree of difficulty with interfaces in C#.)

Because of the inherent difficulty associated with interfaces, I plan to take it slow and easy in explaining the use of interfaces in this and the next few lessons.

Let's build a houseboat

Let's begin with a hypothetical real-world example.  Suppose that you wanted to define a class whose objects represent houseboats.  You could, of course, start from scratch and define a new HouseBoat class. 

A House class and a Boat class

However, let's assume that you already have access to a class named House, which describes the attributes of a house (bedroom, kitchen, heating system, cooling system, etc.).

Let's also assume that you have access to a class named Boat, which describes the attributes of a boat (motor, hull shape, safety equipment, etc.).

A HouseBoat class

If you happen to be a C++ programmer, you could define a new class named HouseBoat, which extends or inherits from the class named House, and which also extends or inherits from the class named Boat.

(This is commonly referred to as multiple inheritance.  A C++ class can extend, or inherit from any number of other classes.) 

An ideal solution

Objects instantiated from your new class would have the attributes of a house, and would also have the attributes of a boat. 

At the surface, this sounds like an ideal solution.  However, many subtle problems arise with the use of multiple inheritance in C++, and it is very easy to make serious programming errors.  As a result, neither Java nor C# allow multiple inheritance.  (At least not in the same way that multiple inheritance is allowed in C++.)  In both Java and C#, a new class is allowed to extend only one other class.

One solution to the problem

Without getting into details of the reasons why, many of the problems associated with multiple inheritance can be avoided if all but one of the extended classes are pure abstract classes.

(For purposes of this discussion, a pure abstract class is a class that contains only abstract methods and possibly constants.)

While such an inheritance structure may not be quite as powerful as the multiple-inheritance structure described for C++ above, this structure does provide many of the benefits of multiple inheritance and it avoids many of the problems.  This is the solution provided by both Java and C#.

An interface is a pure abstract class

An interface in Java and C# meets the above description of a pure abstract class. 

According to C# In A Nutshell,

"An interface provides a specification rather than an implementation for its members.  This is similar to a pure abstract class, which is an abstract class consisting of only abstract members."

Some jargon

As usual, there is some jargon that we must deal with.  For example, we don't say that a class extends or inherits from an interface.  Rather, we say that a class implements an interface.

(This is true even though the C# syntax for implementing an interface is indistinguishable from the syntax for extending a class.)

Back to our HouseBoat example

To handle the previous example in C#, we might have a class named House, and an interface named IBoat.  Our new HouseBoat class could extend the House class and implement the IBoat interface.

(Although not technically required, it is customary in C# to begin the name of an interface with an upper-case "I".  Perhaps this is done to help the reader of the code distinguish between extending a class and implementing an interface, since the syntax doesn't make it possible to distinguish between the two.)

Will quote several authors

In order to understand a new concept, it is often useful to hear what different authors have to say about the concept.  To help you to understand the use of interfaces, I will provide quotations from several authors along with my own comments and explanations.

Visual C#.NET by Joyce Farrell

For example, here is what Joyce Farrell has to say about multiple inheritance in her book entitled Visual C#.NET.  Some of what she has to say echoes what I told you above.

"Multiple inheritance is a difficult concept, and programmers encounter many problems when they use it.  For example, variables and methods in the parent classes may have identical names, which create a conflict when the child class uses one of the names.  Additionally, ... a child class constructor must call its parent class constructor.  When two or more parents exist, this becomes a more complicated task.  ... For all of these reasons, multiple inheritance is prohibited in C#."

What is an interface?

I find it very interesting how different authors provide different descriptions of the interface and its purpose.  Farrell goes on to tell us,

"C# does provide an alternative to multiple inheritance, known as an interface.  Much like an abstract class, an interface is a collection of methods (and perhaps other members) that can be used by any class as long as the class provides a definition to override the interface's abstract definitions."

Interface vs. abstract class

Farrell has this to say about the differences between an interface and an abstract class,

"Abstract classes and interfaces are similar in that you cannot instantiate concrete objects from either one.  Abstract classes differ from interfaces in that abstract classes can contain non-abstract methods, but all methods within an interface must be abstract.  A class can inherit from only one superclass (whether abstract or not), but it can implement any number of interfaces."

The interface definition

Farrell goes on to say,

"You create an interface much as you create an abstract class definition, except that you use the keyword interface instead of abstract class."

C# In A Nutshell, by Drayton, Albabari, and Neward

According to C# In A Nutshell,

"An interface is similar to a class, but with the following major differences:

  • An interface provides a specification rather than an implementation for its members.  This is similar to a pure abstract class, which is an abstract class consisting of only abstract members.
  • A class and a struct can implement multiple interfaces, while a class can inherit only from a single class.
  • A struct can implement an interface, but a struct cannot inherit from a class."

Why use an interface?

Nutshell also tells us,

"An interface is useful when you need multiple classes to share characteristics not present in a common base class.  In addition, an interface is a good way to ensure that these classes provide their own implementation for the interface members, since interface members are implicitly abstract."

Programming C#, by Jesse Liberty

According to Programming C#, by Jesse Liberty,

"An interface is a contract that guarantees to a client how a class or struct will behave." 

In other words, when a class implements an interface, it tells any potential client,

"I guarantee I'll support the methods, properties, events, and indexers of the named interface."

An alternative to an abstract class

Liberty goes on to tell us,

"An interface offers an alternative to an abstract class for creating contracts among classes and their clients.  These contracts are made manifest using the interface keyword, which declares a reference type that encapsulates the contract."

A new type

Stated differently, when you define a class, abstract or otherwise, you introduce a new type into the system.  Similarly, when you define an interface, you also introduce a new type into the system. 

Whereas a class definition defines the behavior of an object of the class type, however, an interface definition simply defines the user interface to an object of the interface type, without saying anything about behavior.  The behavior of the object is defined by the class that implements the interface.

C# Primer, A Practical Approach, by Stanley Lippman

Now let's see what Stanley Lippman has to say in his book entitled C# Primer, A Practical Approach.

Lippman begins by telling us,

"An interface specifies a set of abstract methods and properties.  Like an abstract base class, an interface is made concrete by each of its derived classes.  Unlike an abstract base class, an interface cannot provide a default implementation or define state, such as an instance data member or constant."

In this paragraph, Lippman hits upon one of the minor differences between interfaces in C# and Java.  Java interfaces can contain constants, while C# interfaces cannot contain constants.  I will have more to say about this difference later.

Definition of a simple interface

Figure 1 shows the definition of a simple interface named I1.  This interface declares an (implicitly) public abstract virtual method name p, which takes no parameters and returns nothing.
 
interface I1{
  void p();
}//end interface I1

Figure 1

Must define the method named p

Any class that implements the interface named I1 must define a method named p, whose signature matches that declared in the interface.

May implement p with different behaviors

It is extremely important to note, however, that if two or more classes implement the interface named I1, each of those classes may define the method named p to have different behavior.

If you then instantiate objects of those different classes and invoke the method named p on each of the objects, the behavior resulting from the invocation of p on one object may be radically different from the behavior resulting from the invocation of p on a different object.

Syntax to implement an interface

Listing 2 shows the syntax for causing a class to implement an interface.
 
class B : I1{
  //Add members here
}//end class B

Figure 2

If you have been studying the previous lessons, you will recognize that this syntax is indistinguishable from the syntax used to cause a class to extend another class.  In particular, it is not possible to examine the first line of a class definition and determine whether the name following the colon is the name of a class, or is the name of an interface.

(For those who may be interested, the syntax used by Java clearly differentiates between extending a class and implementing an interface.  On the other hand, the Java syntax is more verbose and requires more typing effort.)

Extending a class and implementing interfaces

Figure 3 shows the syntax for a class named B, which extends the class named A, and which also implements the interfaces named I1 and I2.  Note that the superclass name and the interface names are separated by commas.
 
class B : A,I1,I2{
  //Define interface methods and other
  // methods here.
}//end class B

Figure 3

(Again, however, it is not possible to examine the first line of the class definition and determine whether A is the name of a class or is the name of an interface.)

The required order of the referenced class and the interfaces

Nutshell tells us,

"If a class inherits from a base class, then each interface implemented must appear after the base class." 

In other words, if there is a designated superclass (base class), the reference to the superclass must appear in the list of comma-separated references before any of the references to the interfaces.

When to define an interface

According to Farrell,

"Beginning programmers sometimes find it difficult to decide when to create an abstract superclass and when to create an interface.  Typically you would create an abstract class when you want to provide some data or methods that subclasses can inherit, but you want the subclasses to override some specific methods that you declare to be abstract.  You would create an interface when you want subclasses to override every method."

Non-abstract methods can be overridden

I will make a couple of clarifying comments regarding the above quotation from Farrell. 

First, it is not necessary for a method to be declared abstract in order for it to be overridden in a subclass (but it is necessary that the method be declared virtual).  For example, the Object class defines several virtual methods which are intended to be inherited and used as defined, or to be overridden if their behavior is inappropriate for an object instantiated from the new class.

Multiple inheritance not supported

I will also mention that because C# doesn't support multiple inheritance, it is often necessary to define and use interfaces in situations where another language (such as C++) might use classes instead. 

In other words, if your new class must inherit from some class, the only way to achieve the benefits of multiple inheritance in C# is to cause your new class to also implement one or more interfaces.

Polymorphic behavior with interfaces

Now we have reached my favorite part of this discussion (which is the main topic of this and the next few lessons).

Continuing with Farrell,

"Interfaces provide you with a way to exhibit polymorphic behavior.  If diverse classes implement the same interface in unique ways, then you can treat each class type in the same way using the same language.  When different classes use the same interface, you know the names of the methods that are available with those classes and C# classes adopt a more uniform functionality..."

Nutshell tells us,

"... we defined polymorphism as the ability to perform the same operations on many types, as long as each type shares a common subset of characteristics.  The purpose of an interface is precisely for defining such a set of characteristics."

Lippman tells us,

"Access through an interface allows you to treat the interface polymorphically.  In other words, you can have two or more classes implement the interface, and then by accessing these classes only through the interface, you can ignore their real runtime type and treat them interchangeably."

A simple example of polymorphic behavior

With those three descriptions as background, let me provide a simple example.

Assume that you have several objects instantiated from the hypothetical classes named Circle, Rectangle, and Triangle stored in an array as type IShape.

Assume also that each of the classes listed above implements the hypothetical interface named IShape, which declares a method named area

(Actually, this would be necessary in order to store the object's references in the array as type IShape.)

Assume that the purpose of the method named area, as declared in the interface, is to calculate the area of a shape.

Invoke the area method on any object in the array

Given these circumstances, you could invoke the area method on any of the objects in the array knowing that the calculation of the area will be appropriate for the type of shape involved. 

In fact, you wouldn't even need to be concerned about the actual classes from which the objects were instantiated.  If they all implement IShape, they could all be treated as type IShape.  If they all implement IShape correctly, you could be confident that the value returned from the area method would be correct, regardless of the actual shape involved.

Contents of an interface definition

Lippman tells us,

"The members that an interface is permitted to define are a subset of those permitted for a class.  An interface can declare only methods, properties, indexers, and events as members."

Figure 4 shows the syntax for declaring a method, a property, and an indexer in an interface definition.
 
public interface ISample{
  //A method
  bool isComplete(int item);

  //A read-only property
  bool Done { get; set;}

  //A one-dimensional indexer
  int this[ int number ]{ get; set; }

}//end interface definition

Figure 4

(Note that the property and indexer declarations in Figure 4 do not provide an implementation for get and set, but simply designate that there is a get and a set.  Also, the method declaration does not include a body.)

What is prohibited in an interface?

Lippman tells us,

"An interface cannot define instance data members.  Nor can it define either a constructor or a destructor...  In addition, an interface cannot declare static members.  Because a const member is implicitly static, const members are not allowed, and neither are operators nor, not surprisingly, a static constructor."

Comparison with a Java interface

As mentioned above, a C# interface can contain declarations of properties, events, methods, and indexers.  However, it cannot contain member variables or constants.

A Java interface can only contain method declarations and constants (final variables).  However, because events, properties and indexers (indexed properties) are implemented using methods in Java (unlike C# which requires special syntax for those constructs), a Java interface can contain the same things that can be contained in a C# interface.

Java interface can contain constants

In addition, a Java interface can contain constants.

(A constant, which is really a final variable in Java, is not implicitly static.  In fact, even local variables can be declared final in Java.  Therefore, there is no prohibition against having constants in Java interfaces.)

However, there are other good ways to handle constants in both languages, so the lack of constants in a C# interface should not be viewed as a serious limitation.

A common service for otherwise unrelated types

Lippman states,

"An interface ... provides a common service or characteristic for otherwise unrelated types.  For example, any type wishing to be the target of the foreach statement must implement the IEnumerable interface.

For example, the ArrayList, BindingManager, DataView, and BitArray classes are all derived from the IEnumerable interface, but otherwise they have little in common."

How does Baldwin explain this?

I usually explain this in the following way in the classroom.  I first draw an inheritance hierarchy on the chalkboard, and emphasize that from a type viewpoint, an object of a given class is related only to its ancestors (superclasses) in the hierarchy (parent, grandparent, great-grandparent, etc.).  For example, an object instantiated from a class can be treated as the type of any of its superclasses, but it cannot be treated as the type of a subclass, a sibling, a cousin, an uncle, etc.

A new relationship

However, if two or more classes which have absolutely no relationship up and down the family tree in the inheritance hierarchy implement the same interface, an object instantiated from any of those classes can be treated as a new type (which is the name of the interface).

Furthermore, any of those object's references can be passed as a parameter to any method that expects in incoming parameter of the interface type, and any of the methods declared in the interface can be invoked those object's references.  However, the behavior of a particular method invoked on an object instantiated from one such class may be completely different from the behavior of the same method invoked on an object instantiated from another such class.

Interfaces are meant to be mixed in

Liberty explains,

"Syntactically, an interface is like a class that has only abstract methods.  An abstract class serves as the base class for a family of derived classes, while interfaces are meant to be mixed in with other inheritance trees." 

When different classes implement the same interface, a new relationship among those classes is formed, which has nothing to do with the class inheritance hierarchy.

A form of multiple inheritance

Lippman tells us,

"Unlike classes, which support single inheritance only, interfaces support multiple inheritance.  The System.String class, for example, is derived from four interfaces provided within the System namespace."

Thus, objects instantiated from a class that implements several different interfaces belongs to several different relationships. 

One set of relationships is based on the superclasses of the class in the normal class inheritance hierarchy.  The other relationships are determined by the interfaces implemented by the class.

Be aware, however, that whenever an object of that class is treated as the type of one of the interfaces, the only methods that can be invoked on the object are those methods declared in the interface.  If you need to invoke methods declared in a different interface, a cast must be used to change the type of the object's reference.

The letter and the spirit of the interface

Here is another quotation from Lippman that I particularly like.

"Not only do we have to provide a definition of every interface member, but we must implement the documented behavior of each member if we want our implementation to transparently meld with the other implementations of that interface.  In addition, we need to throw the same exceptions under the same abnormal conditions.  The compiler cannot enforce this."

A simple example

Perhaps I can explain what this means by providing a concrete example.  Consider the interface in the C# library named ICollection.  Objects of many classes, such as Hashtable, Stack, and Queue, (that are used to store collections of object references), implement this interface.

The documentation for this interface lists three properties, one of which is Count.  The documentation for the property named count reads as follows:

"When implemented by a class, gets the number of elements contained in the ICollection."

While the documentation for the Count property is very simple, it is also very specific.

To begin with, there is the implication that when you define a class that implements ICollection, an object of that class will be capable of storing a collection of object references.  Further, when you write the code that implements the Count property, it is incumbent on you to write code that will get and return the number of elements contained in the collection.

Can't be forced by the compiler

There is no way that the compiler can force you to comply with the instructions in the documentation.  For example, as long as your Count method returns an int, the compiler has no way of knowing if the int value returned is correct according to the documented requirements.  It is up to you to read and understand the documentation, and to write code that will satisfy the documented requirements.

More on the interface members

Continuing with Lippman,

"All members of an interface are implicitly abstract.  We cannot provide a default implementation, however trivial.  In addition, the members of the interface are implicitly public.  We cannot modify a member with either the abstract or the public keyword."

In other words, don't attempt to declare the members of the interface either abstract or public, but be aware that when you define an interface method in a class, you are effectively overriding a public abstract virtual method.

Multiple inheritance for interfaces

An interface can extend or inherit from one or more other interfaces using the syntax shown in Figure 5.
 
public interface ISample : 
               ICollection, ICloneable{
  //members
}//end interface definition

Figure 5

The interface named ISample in Figure 5 extends both ICollection and ICloneable.

When a class implements an interface, which in turn extends other interfaces, the class must define all the methods that are declared in the implemented interface, plus all the methods inherited into that interface.  (I will show you an example of this in a future lesson.)

Interfaces inherit from the Object class

An interface cannot explicitly inherit from a class or a struct.  However, interfaces implicitly inherit from the root class named Object.  Among other things, this means that when an object's reference is being treated as an interface type, you can invoke any of the methods defined in the Object class (such as ToString) on that reference.

The difference between is-a and implements

Liberty discusses the difference between the is-a relationship and the implements relationship.  As an example, he explains,

"These two relationships are subtly differently.  A car is a vehicle, but it might implement the CanBeBoughtWithABigLoan capability (as can a house, for example)"

In other words, Liberty is saying that a house and a car would typically have no relationship in a normal class hierarchy.  (It is unlikely that a Car class would be a subclass of a House class, and vice versa.)  However, they do have a relationship that is independent of the class hierarchy.  That relationship is that they are both very expensive, and most people need to take out a big loan to purchase one.

Sleazy Jack's Finance Company

In the above example the CanBeBoughtWithABigLoan interface might declare a method named makeLoan

Assuming that the Car class and the House class both implement this interface, they would both be required to define the makeLoan method.  However, the behavior of the method, as defined in the House class might be radically different from the behavior of the same method as defined in the Car class.

For example, the makeLoan method in the House class might indicate the need to visit a mortgage company, to fill out lots of forms, to be very patient waiting for approval, and to make house payments for thirty years.

The makeLoan method in the Car class might indicate the need to visit Sleazy Jack's Finance Company, to sign one form, to drive out the same day, and to continue paying for the car for the rest of your life.

Using the current jargon, in each case, the behavior of the method would be appropriate for an object instantiated from the class (on second thought, visiting Sleazy Jack might not be an appropriate way to finance a car).

The is operator versus the as operator

When working with objects as interface types, it is often necessary to cast from one interface type to another.  If you attempt a cast that is not possible, an exception will be thrown.

Nutshell tells us,

"The is operator tests whether an object is or derives from a specified class (or implements an interface).  It is often used to perform a test before a downcast."

Before casting a reference to an interface type, you might want to use the is operator to confirm that the object implements the interface, as shown in Figure 6.  In other words, you might want to confirm in advance that the cast is possible so as to avoid the possibility of having to deal with an exception.
 
if(abc is IOk){
  IOk x = (IOk)abc;
  //do something using x
}//end if statement
else ...//do something else

Figure 6

The code in Figure 6 uses the is operator to confirm that the object referred to by abc implements the interface named IOk.  If so, the reference is cast to type IOk, and is stored in the reference variable of type IOk named x.

A more efficient approach

Liberty tells us that there is a more efficient approach that makes use of the as operator instead of the is operator, as shown in Figure 7.
 
IOk x = abc as IOk;
if(x != null){
  //do something using x
}//end if
else ...//do something else

Figure 7

Again, Nutshell tells us,

"The as operator makes a downcast that evaluates to null if the downcast fails."

The first statement in Listing 7 above attempts to:

  • Extract the contents of the variable named abc
  • Change the type of the extracted contents to type IOk
  • Save the result in the variable named x

If it is not possible to convert the contents of abc to type IOk, the expression to the right of the assignment operator in the first statement will evaluate to null without throwing an exception.

The contents of x are then tested for null to determine if the cast was successful.

Why is this more efficient?

I'm not going to try to explain why the second approach is more efficient than the first.  It has to do with how the code is compiled into the intermediate language.  You can refer to Liberty's book if you want more information in this regard.  However, I did want to let you know that there are two ways to change the type of a reference from one type to another.  One way is to use a standard cast.  The other way is to use the as operator.  Furthermore, according to Liberty, the use of the as operator is the more efficient of the two.

Overriding interface methods in a subclass

Liberty tells us,

"An implementing class is free to mark any or all of the methods that implement the interface as virtual." 

As a result, when a class implements an interface, subclasses of that class can override the methods to provide different implementations.

Name collisions

Nutshell tells us,

"If there is a name collision between an interface member and an existing member in the class or struct, C# allows you to explicitly implement an interface member to resolve the conflict."

I won't elaborate on this issue.  Rather, if you have a problem with name collisions, you know that you can find the solution in Nutshell.

Summary

In this lesson, I have provided an introduction to interfaces in C#, and have compared them with interfaces in Java.

What's Next?

In the next several lessons, I will explain the use of polymorphism based on method overriding through the C# interface.


Copyright 2002, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, Texas) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which has gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

-end-


© 1996, 1997, 1998, 1999, 2000, 2001, 2002 Richard G. Baldwin