An interface is a named collection of semantically related abstract members.
An interface is like a class, but with three major differences:
The purpose of an interface is to define a common set of characteristics to be shared among many types, which will provide an ability to perform the same operations on these types - polymorphism.
public interface IPointy {
byte GetNumberOfPoints(); // Implicitly public and abstract
}
public class Hexagon : Shape, IPointy
{
public Hexagon(){ }
public Hexagon(string name) : base(name){ }
public byte GetNumberOfPoints(){return 6;}
}
public class Triangle : Shape,
IPointy {
public Triangle(){ }
public Triangle(string name) : base(name){ }
public byte GetNumberOfPoints(){return 3;}
}
Hexagon hex = new Hexagon();
Console.WriteLine("Points: {0}",
hex.GetNumberOfPoints());
//Safely cast for interface reference.
Circle c = new Circle("Circle 1");
IPointy itfPt;
try{
itfPt = (IPointy)c;
Console.WriteLine(itfPt.GetNumberOfPoints());
}
catch(InvalidCastException e){
Console.WriteLine("OOPS! Not Pointy...");
}
// Second way to test for an interface.
Hexagon hex = new Hexagon("Hexagon 2");
IPointy itfPt;
itfPt = hex as IPointy;
if (itfPt != null)
Console.WriteLine(itfPt.GetNumberOfPoints());
else
Console.WriteLine("OOPS! Not Pointy...");
// Third way to test for an interface.
Triangle t = new Triangle();
if (t is IPointy)
Console.WriteLine(t.GetNumberOfPoints());
else
Console.WriteLine("OOPS! Not Pointy...");
interface IBasicCar {
void Drive(); }
interface IUnderWaterCar {
void Dive(); }
interface IJamesBondCar : IBaseCar,
IUnderWaterCar {
void TurboBoost(); }
public class JBCar : IJamesBondCar {
public JBCar() {}
void IBasicCar.Drive() {
Console.WriteLine("Speeding up..."); }
void IUnderWaterCar.Dive() {
Console.WriteLine("Submerging..."); }
void IJamesBondCar.TurboBoost() {
Console.WriteLine("Blast off!"); }
}
JBCar j = new JBCar();
if (j is IJamesBondCar) {
((IJamesBondCar)j).Drive();
((IJamesBondCar)j).TurboBoost();
((IJamesBondCar)j).Dive();
}
| Interface Name | Meaning in Life |
| ICollection | Defines generic characteristics (e.g., read-only, thread safe, etc.) for a collection class |
| IComparer | Allows two object to be compared |
| IDictionary | Allows an object to represent its contents using name/value pairs |
| IDictionaryEnumerator | Used to enumerate the contents of an object supporting IDictionary |
| IEnumerable | Returns the IEnumerator interface for a given object |
| IEnumerator | Generally used to support foreach-style iteration of subtypes |
| IHashCodeProvider | Returns the hash code for the implementing type using a customized hash algorithm |
| IList | Provides behavior to add, remove, and index items in a list of objects |
Most of the classes defined within System.Collections namespace implement these interfaces to provide access to their contents.
| Class Name | Key Implemented Interfaces |
| ArrayList | IList, ICollection, IEnumerable, and ICloneable |
| Hashtable | IDictionary, ICollection, IEnumerable, and ICloneable |
| Queue | ICollection, ICloneable, and IEnumerable |
| SortedList | IDictionary, ICollection, IEnumerable, and ICloneable |
| Stack | ICollection and IEnumerable |
Interfaces are commonly used as a callback mechanism.
// The callback interface.
public interface IEngineEvents{
void AboutToBlow(string msg);
void Exploded(string msg);
}
Event interfaces are not typically implemented directly by the client executable, but rather by a helper sink object, upon which the sender of the events will make calls.
//Car event sink.
public class CarEventSink : IEngineEvents
{
private string name; // Diagnostic member to identify sink.
public CarEventSink() {}
public CarEventSink(string sinkName) {
name = sinkName; }
public void AboutToBlow(string msg) {
Console.WriteLine("{0} reporting: {1}", name, msg); }
public void Exploded(string msg) {
Console.WriteLine("{0} reporting: {1}", name, msg); }
}
Next task is to pass a reference to this sink into the Car type. The Car holds onto the reference, and makes calls back on the sink when appropriate.
public class Car {
...
// The set of connected sinks
ArrayList itfConnections = new ArrayList();
// Attach or disconnect from the source of events
public void Advise(IEngineEvents itfClientImpl) {
itfConnections.Add(itfClientImpl); }
public void Unadvise(IEngineEvents itfClientImpl) {
itfConnections.Remove(itfClientImpl); }
public void SpeedUp(int delta) {
// If the car is dead, send exploded event to each sink.
if(carIsDead) {
foreach(IEngineEvents e in itfConnections)
e.Exploded("Sorry, this car is dead...");
}
else {
currSpeed += delta;
// Dude, you're almost dead! Proceed with caution!
if(10 == maxSpeed - currSpeed) {
foreach(IEngineEvents e in itfConnections)
e.AboutToBlow("Careful buddy! Gonna blow!");
}
if(currSpeed >= maxSpeed)
carIsDead = true;
else
Console.WriteLine("\tCurrSpeed = {0} ", currSpeed);
}
}
Client-side code.
//Make a car and listen to the events.
public class CarApp {
public static int Main(string[] args) {
Car c1 = new Car("SlugBug", 100, 10);
// Make sink object.
CarEventSink sink = new CarEventSink();
// Pass the Car a reference to the sink.
c1.Advise(sink);
// Speed up (this will generate the events).
for(int i = 0; i < 6; i++)
c1.SpeedUp(20);
// Detach from events.
c1.Unadvise(sink);
return 0;
}
}