Defining Interfaces using C An interface is nothing

  • Slides: 22
Download presentation
Defining Interfaces using C# • An interface is nothing more than a named collection

Defining Interfaces using C# • An interface is nothing more than a named collection of semantically related abstract members. • An interface expresses a behavior that a given class or structure may choose to support. • At a syntactic level, an interface is defined using the C# interface keyword. • Unlike other. NET types, interfaces never specify a base class and contain members that do not take an access modifier

// This interface defines the behavior of "having points. " public interface IPointy {

// This interface defines the behavior of "having points. " public interface IPointy { // Implicitly public and abstract. byte Get. Number. Of. Points(); } The IPointy interface defines a single method. However, . NET interface types are also able to define any number of properties. For example, you could create the IPointy interface to use a read-only property rather than a traditional accessor method: // The pointy behavior as a read-only property. public interface IPointy { byte Points { get; } }

 • You cannot allocate interface types as you would a class or structure:

• You cannot allocate interface types as you would a class or structure: // Ack! Illegal to "new" interface types. static void Main(string[] args) { IPointy p = new IPointy(); // Compiler error! } * Interfaces do not bring much to the table until they are implemented by a class or structure. Here, IPointy is an interface that expresses the behavior of “having points. ” The idea is simple: Some classes in the Shapes hierarchy have points (such as the Hexagon), while others (such as the Circle) do not. If you configure Hexagon and Triangle to implement the IPointy interface, you can safely assume that each class now supports a common behavior, and therefore a common set of members.

Implementing an Interface using C# • When a class (or structure) chooses to extend

Implementing an Interface using C# • When a class (or structure) chooses to extend its functionality by supporting interface types, it does so using a comma-delimited list in the type definition. • Be aware that the direct base class must be the first item listed after the colon operator. • When your class type derives directly from System. Object, you are free to simply list the interface(s) supported by the class, as the C# compiler will extend your types from System. Object if you do not say otherwise. • On a related note, given that structures always derive from System. Value. Type. // This class derives from System. Object and implements single interface. public class Some. Class : ISome. Interface { // Some Code }

//Class derives from custom base class and implements a single interface. public class Another.

//Class derives from custom base class and implements a single interface. public class Another. Class : My. Base. Class, ISome. Interface { // Some Code } // This struct derives from System. Value. Type and implements two //interfaces. public struct Some. Struct : ISome. Interface, IPointy { // Some Code }

// Hexagon now implements IPointy. public class Hexagon : Shape, IPointy { public Hexagon(){

// Hexagon now implements IPointy. public class Hexagon : Shape, IPointy { public Hexagon(){ } public Hexagon(string name) : base(name){ } public override void Draw() { Console. Write. Line("Drawing {0} the Hexagon", Pet. Name); } } // IPointy Implementation. public byte Points { get { return 6; } }

// New Shape derived class named Triangle. public class Triangle : Shape, IPointy {

// New Shape derived class named Triangle. public class Triangle : Shape, IPointy { public Triangle() { } public Triangle(string name) : base(name) { } public override void Draw() { Console. Write. Line("Drawing {0} the Triangle", Pet. Name); } } // IPointy Implementation. public byte Points { get { return 3; } } 31, 37, 39, 41, 42, 43, 45, 46,

Invoking Interface Members at the Object Level public static void Main(string[] args) { //

Invoking Interface Members at the Object Level public static void Main(string[] args) { // Call new Points member defined by IPointy Hexagon hex = new Hexagon(); Console. Write. Line("Points: {0}", hex. Points); } • This approach works fine in this particular case, given that you are well aware that the Hexagon type has implemented the interface in question. Other times, however, you will not be able to determine at compile time which interfaces are supported by a given type. • Obtaining Interface References: Explicit Casting try public static void Main() { { ipt = (IPointy)c; //boxing or explicit casting. . . Console. Write. Line(ipt. Points); // Catch a possible Invalid. Cast. Exception } Circle c = new Circle(“John"); catch (Invalid. Cast. Exception e) IPointy ipt; { Console. Write. Line(e. Message); } }

Obtaining Interface References: The as Keyword public static void Main(string[] args) Obtaining Interface References:

Obtaining Interface References: The as Keyword public static void Main(string[] args) Obtaining Interface References: The is {. . . Keyword // Can we treat hex 2 as IPointy? Hexagon h = new Hexagon("Ram"); //third way to test for an interface IPointy ipt = h as IPointy; Triangle t = new Triangle(); if(ipt != null) if(t is IPointy) Console. Write. Line("Points: {0}", ipt. Points); Console. Write. Line(t. Points); else Else Console. Write. Line("OOPS! Not pointy. . . "); Console. Write. Line(“OOPS! Not pointy. . . "); } Exercising the Shapes Hierarchy public static void Main(string[] args) {. . . Shape[ ] s = { new Hexagon(), new Circle(), new Triangle("Ram"), new Circle("Sham")} ; for(int i = 0; i < s. Length; i++)

{ // Recall the Shape base class defines an abstract Draw() // member, so

{ // Recall the Shape base class defines an abstract Draw() // member, so all shapes know how to draw themselves. s[i]. Draw(); if(s[i] is IPointy) Console. Write. Line("Points: {0} ", ((IPointy)s[i]). Points); else Console. Write. Line("{0} is not a pointy!", s[i]. Pet. Name); } } Interfaces As Parameters // Models the ability to render a type in stunning 3 D. public interface IDraw 3 D { void Draw 3 D(); } // Hexagon supports IPointy and IDraw 3 D public class Hexagon : Shape, IPointy, IDraw 3 D // Circle supports IDraw 3 D { public class Circle : Shape, IDraw 3 D. . . { public void Draw 3 D() Console. Write. Line("Drawing Hexagon in 3 D!"); { Console. Write. Line("Drawing Circle in 3 D!"); } }

Building Interface Hierarchies // The base interface. public interface IDrawable { void Draw(); }

Building Interface Hierarchies // The base interface. public interface IDrawable { void Draw(); } public interface IPrintable : IDrawable { void Print(); } public interface IMeta. File. Render : IPrintable { void Render(); } // This class supports IDrawable, IPrintable, and IMeta. File. Render. public class Super. Image : IMeta. File. Render { public void Draw() { Console. Write. Line("Basic drawing logic. "); } public void Print() { Console. Write. Line("Draw to printer. "); } public void Render() { Console. Write. Line("Render to metafile. "); } }

// This class supports IDrawable, IPrintable, and IMeta. File. Render. public class Super. Image

// This class supports IDrawable, IPrintable, and IMeta. File. Render. public class Super. Image : IMeta. File. Render { public void Draw() { Console. Write. Line("Basic drawing logic. "); } public void Print() { Console. Write. Line("Draw to printer. "); } public void Render() { Console. Write. Line("Render to metafile. "); } } // Exercise the interfaces. static void Main(string[] args) { Super. Image si = new Super. Image(); // Get IDrawable itf. Draw = (IDrawable)si; itf. Draw(); // Now get Imeta. File. Render, which exposes all methods up // the chain of inheritance. if (itf. Draw is IMeta. File. Render) { IMeta. File. Render itf. MF = (IMeta. File. Render)itf. Draw; itf. MF. Render(); itf. MF. Print(); }

Interfaces with Multiple Base Interfaces public interface ICar { void Drive(); } public interface

Interfaces with Multiple Base Interfaces public interface ICar { void Drive(); } public interface IUnderwater. Car { void Dive(); } // Here we have an interface with TWO base interfaces. public interface IJames. Bond. Car : ICar, IUnderwater. Car { void Turbo. Boost(); } If you were to build a class that implements IJames. Bond. Car, you would now be Responsible for implementing Turbo. Boost(), Dive(), and Drive():

public class James. Bond. Car : IJames. Bond. Car { public void Drive() {

public class James. Bond. Car : IJames. Bond. Car { public void Drive() { Console. Write. Line("Speeding up. . . "); } public void Dive() { Console. Write. Line("Submerging. . . "); } public void Turbo. Boost() { Console. Write. Line("Blast off!"); } } This specialized automobile can now be manipulated as you would expect: static void Main(string[] args) {. . . James. Bond. Car j = new James. Bond. Car(); j. Drive(); j. Turbo. Boost(); j. Dive(); }

Building a Custom Enumerator (IEnumerable and IEnumerator) • Here, we will examine the role

Building a Custom Enumerator (IEnumerable and IEnumerator) • Here, we will examine the role of IEnumerable and IEnumerator • Assume you have developed a class named Garage that contains a set of individual Car types stored within a System. Array: // This seems reasonable. . . public class Program // Garage contains a set of Car objects. { public class Garage static void Main(string[] args) { { private Car[] car. Array; Garage car. Lot = new Garage(); // Fill with some Car objects upon startup. public Garage() foreach (Car c in car. Lot) { { car. Array = new Car[4]; Console. Write. Line("{0} is going {1} MPH", car. Array[0] = new Car("Rusty", 30); c. Pet. Name, c. Curr. Speed); car. Array[1] = new Car("Clunker", 55); } car. Array[2] = new Car("Zippy", 30); } car. Array[3] = new Car("Fred", 30); } } } The compiler informs you that the Garage class does not implement a method named Get. Enumerator(). This method is formalized by the IEnumerable interface, which is found lurking within the System. Collections namespace

// This interface informs the caller that the object's subitems can // be enumerated.

// This interface informs the caller that the object's subitems can // be enumerated. public interface IEnumerable { IEnumerator Get. Enumerator(); } The Get. Enumerator() method returns a reference to yet another interface named System. Collections. IEnumerator. This interface provides the infrastructure to allow the caller to traverse the internal objects contained by the IEnumerable-compatible container: // This interface allows the caller to obtain a container's subitems. public interface IEnumerator { bool Move. Next (); // Advance the internal position of the cursor. object Current { get; } // Get the current item (read-only property). void Reset (); // Reset the cursor before the first member. } As the System. Array type (as well as many other types) already implements IEnumerable and IEnumerator, you can simply delegate the request to the System. Array as follows:

using System. Collections; . . . public class Garage : IEnumerable { // System.

using System. Collections; . . . public class Garage : IEnumerable { // System. Array already implements IEnumerator! private Car[] car. Array; public Garage() { car. Array = new Car[4]; car. Array[0] = new Car("Fee. Fee", 200, 0); car. Array[1] = new Car("Clunker", 90, 0); car. Array[2] = new Car("Zippy", 30, 0); car. Array[3] = new Car("Fred", 30, 0); } public IEnumerator Get. Enumerator() { // Return the array object's IEnumerator. return car. Array. Get. Enumerator(); } } // Manually work with IEnumerator i = car. Lot. Get. Enumerator(); i. Move. Next(); Car my. Car = (Car)i. Current; Console. Write. Line("{0} is going {1} MPH", my. Car. Pet. Name, my. Car. Curr. Speed);

Exploring the System. Collections Namespace The System. Collections namespace defines a number of interfaces.

Exploring the System. Collections Namespace The System. Collections namespace defines a number of interfaces. System. Collections Interface Meaning ICollection Defines generic characteristics (e. g. , count and thread safety) for a collection type. IComparer IDictionary. Enumerator Defines methods to support the comparison of objects for equality. Allows an object to represent its contents using name/value pairs. Enumerates the contents of a type supporting IDictionary. IEnumerable Returns the IEnumerator interface for a given object. IEnumerator Generally supports foreach-style iteration of subtypes. IHash. Code. Provider 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. IDictionary

The Class Types of System. Collections Class Array. List Meaning Key Implemented Interfaces Represents

The Class Types of System. Collections Class Array. List Meaning Key Implemented Interfaces Represents a dynamically sized array of objects. IList, ICollection, IEnumerable, and ICloneable Hashtable Represents a collection of objects identified by a numerical key. Custom types stored in a Hashtable should always override System. Object. Get. Hash. Code(). IDictionary, ICollection, IEnumerable, and ICloneable Queue Represents a standard first-in, first-out (FIFO) queue. Like a dictionary; however, the elements can also be accessed by ordinal position (e. g. , index). ICollection, ICloneable, and IEnumerable IDictionary, ICollection, IEnumerable, and ICloneable A last-in, first-out (LIFO) queue providing push and pop (and peek) functionality. ICollection, ICloneable, and IEnumerable Sorted. List Stack Working with the Array. List Type The Array. List type is bound to be your most frequently used type in the System. Collections namespace in that it allows you to dynamically resize the contents at your whim

static void Main(string[] args) { // Create Array. List and fill with some initial

static void Main(string[] args) { // Create Array. List and fill with some initial values. Array. List car. Ar. List = new Array. List(); car. Ar. List. Add. Range(new Car[ ] { new Car("Fred", 90, 10), new Car("Mary", 100, 50), new Car("MB", 190, 11)}); Console. Write. Line("Items in car. Ar. List: {0}", car. Ar. List. Count); // Print out current values. foreach(Car c in car. Ar. List) Console. Write. Line("Car pet name: {0}", c. Pet. Name); // Insert a new item. Console. Write. Line("n->Inserting new Car. "); car. Ar. List. Insert(2, new Car("The. New. Car", 0, 12)); Console. Write. Line("Items in car. Ar. List: {0}", car. Ar. List. Count); // Get object array from Array. List and print again. object[] array. Of. Cars = car. Ar. List. To. Array(); for(int i = 0; i < array. Of. Cars. Length; i++) { Console. Write. Line("Car pet name: {0}", (Car)array. Of. Cars[i]). Pet. Name); } } Here you are making use of the Add. Range() method to populate your Array. List with a set of Car types

Working with the Queue Type Queues are containers that ensure items are accessed using

Working with the Queue Type Queues are containers that ensure items are accessed using a first-in, first-out manner. When you are modeling a scenario in which items are handled on a first-come, first-served basis, System. Collections. Queue is your type of choice. Member of System. Collection. Queue Dequeue() Enqueue() Peek() Meaning Removes and returns the object at the beginning of the Queue Adds an object to the end of the Queue Returns the object at the beginning of the Queue without removing it Building Comparable Objects (IComparable) The System. IComparable interface specifies a behavior that allows an object to be sorted based on some specified key. Here is the formal definition: // This interface allows an object to specify its relationship //between other like objects. public interface IComparable { int Compare. To(object o); }

public class Car {. . . private int car. ID; public int ID {

public class Car {. . . private int car. ID; public int ID { get { return car. ID; } set { car. ID = value; } } public Car(string name, int curr. Sp, int id) { curr. Speed = curr. Sp; pet. Name = name; car. ID = id; }. . . }