Docsity
Docsity

Prepare for your exams
Prepare for your exams

Study with the several resources on Docsity


Earn points to download
Earn points to download

Earn points by helping other students or get them with a premium plan


Guidelines and tips
Guidelines and tips

About interface and array collections, Papers of Computer Science

Notes on interface and collections

Typology: Papers

2022/2023

Uploaded on 10/02/2023

drama-kc
drama-kc 🇮🇳

4 documents

1 / 29

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
1
Interfaces and Collections
Defining Interfaces in C#
An interface is a named collection of semantically related abstract members.
The specific members defined by an interface depend on the exact behavior it is modeling.
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 (not even System.Object) and contain members
that do not take an access modifier (as all interface members are implicitly public).
public interface IPointy
{
// Implicitly public and abstract.
byte GetNumberOfPoints();
}
As you can see, 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:
public interface IPointy
{
byte Points{get;}
}
Can’t create instance for an interface:
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.
Implementing an Interface in 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.
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.
structures always derive from System.ValueType, simply list each interface directly after the structure
definition.
// This class derives from System.Object and implements a single interface.
public class SomeClass : ISomeInterface
{...}
// This class also derives from System.Object and implements a single interface.
public class MyClass : object, ISomeInterface
{...}
// This class derives from a custom base class and implements a single interface.
public class AnotherClass : MyBaseClass, ISomeInterface
{...}
// This struct derives from System.ValueType and implements two interfaces.
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d

Partial preview of the text

Download About interface and array collections and more Papers Computer Science in PDF only on Docsity!

Interfaces and Collections

Defining Interfaces in C#

  • An interface is a named collection of semantically related abstract members.
  • The specific members defined by an interface depend on the exact behavior it is modeling.
  • 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 (not even System.Object) and contain members that do not take an access modifier (as all interface members are implicitly public). public interface IPointy { // Implicitly public and abstract. byte GetNumberOfPoints(); }
  • As you can see, 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: public interface IPointy { byte Points{get;} }
  • Can’t create instance for an interface: 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. Implementing an Interface in 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.
  • 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.
  • structures always derive from System.ValueType, simply list each interface directly after the structure definition. // This class derives from System.Object and implements a single interface. public class SomeClass : ISomeInterface {...} // This class also derives from System.Object and implements a single interface. public class MyClass : object, ISomeInterface {...} // This class derives from a custom base class and implements a single interface. public class AnotherClass : MyBaseClass, ISomeInterface {...} // This struct derives from System.ValueType and implements two interfaces.

public struct SomeStruct : ISomeInterface, IPointy {...}

  • If you are implementing an interface that defines ten members, the type is now responsible for fleshing out the details of the ten abstract entities. // Hexagon now implements IPointy. public class Hexagon : Shape, IPointy { public Hexagon(){ } public Hexagon(string name) : base(name){ } public override void Draw() { Console.WriteLine("Drawing {0} the Hexagon", PetName); } // IPointy Implementation. public byte Points { get { return 6; } } } // New Shape derived class named Triangle. public class Triangle : Shape, IPointy { public Triangle() { } public Triangle(string name) : base(name) { } public override void Draw() { Console.WriteLine("Drawing {0} the Triangle", PetName); } // IPointy Implementation. public byte Points { get { return 3; } } }
  • Each class now returns its number of points to the caller when asked to do so.
  • Contrasting Interfaces to Abstract Base Classes
  • c# allows you to build abstract class types containing abstract methods.
  • LikeLike an interface, when a class derives from an abstract base class, it is also under obligation to flesh out the details of the abstract methods
  • Abstract base classes are free to define public, private, and protected state data, as well as any number of concrete methods that can be accessed by the subclasses.

if (o is Class1) { Console.WriteLine("o is Class1"); a = (Class1)o; }

else if (o is Class2)

Console.WriteLine("o is Class2");

b = (Class2)o;

else

Console.WriteLine("o is neither Class1 nor Class2.");

public static void Main()

Class1 c1 = new Class1();

Class2 c2 = new Class2();

Test(c1);

Test(c2);

Test("Passing String Value instead of class");

Console.ReadKey();

  • In the above example, I'll be checking whether object o is a class or not.
  • If the argument passed is not a class then the application will jump to the message 'o is neither class1 nor class2'. as Operator
  • The "as" operator is used to perform conversions between compatible types.
  • Actually, the "as" operator fulfills a similar role like "is" but in a slightly truncated manner. syntax : expression as type Example of the "as" operator:

using System;

class Class

class Class

public class IsTest

public static void Main()

object [] myObjects = new object [6];

myObjects[0] = new Class1();

myObjects[1] = new Class2();

myObjects[2] = "string";

myObjects[3] = 32;

myObjects[4] = null ;

for ( int i = 0; i < myObjects.Length; ++i)

string s = myObjects[i] as string ;

Console.Write("{0}:", i);

if (s != null )

Console.WriteLine("'" + s + "'");

else

Console.WriteLine("not a string");

Console.ReadKey();

In the above example, each and every value is being cast to a string using the "as" operator and assigned to a string variable which is shown on the console. Invoking Interface Members at the Object Level

  • The most straightforward way to interact with functionality supplied by a given interface is to invoke the methods directly from the object level.
  • For example: static void Main(string[] args) { // Call new Points member defined by IPointy. Hexagon hex = new Hexagon(); Console.WriteLine("Points: {0}", hex.Points); Console.ReadLine(); }
  • 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.
  • For example, assume you have an array containing 50 Shape-compatible types, only some of which support IPointy. Obviously, if you attempt to invoke the Points property on a type that has not implemented IPointy, you receive a compile-time error.
  • The first way you can determine at runtime if a type supports a specific interface is to make use of an explicit cast.Ifthe type does not supportthe requested interface, you receive an InvalidCastException.
  • To handle this possibility gracefully, make use of structured exception handling, for example: static void Main(string[] args)

if(s[i] is IPointy) Console.WriteLine("-> Points: {0} ", ((IPointy)s[i]).Points); else Console.WriteLine("-> {0}'s not pointy!", s[i].PetName); } } The output follows in Figure 7-2. Interfaces As Parameters

  • Interfaces are valid .NET types, you may construct methods that take interfaces as parameters. // Models the ability to render a type in stunning 3D. public interface IDraw3D { void Draw3D(); } // Circle supports IDraw3D. public class Circle : Shape, IDraw3D { ... public void Draw3D() { Console.WriteLine("Drawing Circle in 3D!"); } } // Hexagon supports IPointy and IDraw3D. public class Hexagon : Shape, IPointy, IDraw3D { ... public void Draw3D() { Console.WriteLine("Drawing Hexagon in 3D!"); } } public class Program { // I'll draw anyone supporting IDraw3D. public static void DrawIn3D(IDraw3D itf3d) { Console.WriteLine("-> Drawing IDraw3D compatible type"); itf3d.Draw3D(); } static void Main() {

Shape[] s = { new Hexagon(), new Circle(), new Triangle(), new Circle("JoJo")} ; for(int i = 0; i < s.Length; i++) { ... // Can I draw you in 3D? if(s[i] is IDraw3D) DrawIn3D((IDraw3D)s[i]); } } } Interfaces As Return Values

  • Interfaces can also be used as method return values. // This method tests for IPointy-compatibility and, // if able, returns an interface reference. static IPointy ExtractPointyness(object o) { if (o is IPointy) return (IPointy)o; else return null; } static void Main(string[] args) { // Attempt to get IPointy from Car object. Car myCar = new Car(); IPointy itfPt = ExtractPointyness(myCar); if(itfPt != null) Console.WriteLine("Object has {0} points.", itfPt.Points); else Console.WriteLine("This object does not implement IPointy"); } Arrays of Interface Types
  • Same interface can be implemented by numerous types, even if they are not within the same class hierarchy.
  • This can yield some very powerful programming constructs.
  • For example, assume that you have developed a brand new class hierarchy modeling kitchen utensils and another modeling gardening equipment.
  • Although these hierarchies are completely unrelated from a classical inheritance point of view, you can treat them polymorphically using interface-based programming.
  • To illustrate, assume you have an array of IPointy-compatible objects. Given that these members all support the same interface, you are able to iterate through the array and treat each object as an IPointy-compatible object, regardless of the overall diversity of the class hierarchies: static void Main(string[] args) { // This array can only contain types that // implement the IPointy interface. IPointy[] myPointyObjects = {new Hexagon(), new Knife(),

IDraw3D i3d = (IDraw3D)myLine; i3d.Draw(); Resolving Name Clashes

  • Explicit interface implementation can also be very helpful whenever you are implementing a number of interfaces that happen to contain identical members.
  • For example, assume you wish to create a class that implements all the following new interface types: // Three interfaces each define identically named methods. public interface IDraw { void Draw(); } public interface IDrawToPrinter { void Draw(); } public class SuperImage : IDraw, IDrawToPrinter, IDraw3D { void IDraw.Draw() { /* Basic drawing logic. / } void IDrawToPrinter.Draw() { / Printer logic. / } void IDraw3D.Draw() { / 3D rendering logic. */ } } Building Interface Hierarchies
  • Just as a class can serve as a base class to other classes (which can in turn function as base classes to yet another class), it is possible to build inheritance relationships among interfaces.
  • The topmost interface defines a general behavior, while the most derived interface defines more specific behaviors.
  • To illustrate, ponder the following interface hierarchy: // The base interface. public interface IDrawable { void Draw();} public interface IPrintable : IDrawable { void Print(); } public interface IMetaFileRender : IPrintable { void Render(); } Figure 7- 5 illustrates the chain of inheritance.
  • Any methods defined by the baseinterface(s) are automatically carried into the definition. For example: // This class supports IDrawable, IPrintable, and IMetaFileRender. public class SuperImage : IMetaFileRender { public void Draw() { Console.WriteLine("Basic drawing logic."); } public void Print() { Console.WriteLine("Draw to printer."); } public void Render() { Console.WriteLine("Render to metafile."); } } // Exercise the interfaces. static void Main(string[] args) { SuperImage si = new SuperImage(); // Get IDrawable. IDrawable itfDraw = (IDrawable)si; itfDraw.Draw(); // Now get ImetaFileRender, which exposes all methods up // the chain of inheritance. if (itfDraw is IMetaFileRender) { IMetaFileRender itfMF = (IMetaFileRender)itfDraw; itfMF.Render(); itfMF.Print(); } Console.ReadLine(); } Interfaces with Multiple Base Interfaces
  • You can create an interface that derives from multiple base interfaces.
  • Example: public interface ICar
  • the GetEnumerator() 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 MoveNext (); // 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.

  • If you wish to update the Garage type to support these interfaces, you could take the long road and

implement each method manually.

  • While you are certainly free to provide customized versions of GetEnumerator(), MoveNext(),

Current, and Reset(), there is a simpler way.

  • 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.Array already implements IEnumerator!

private Car[] carArray;

public Garage()

carArray = new Car[4];

carArray[0] = new Car("FeeFee", 200, 0);

carArray[1] = new Car("Clunker", 90, 0);

carArray[2] = new Car("Zippy", 30, 0);

carArray[3] = new Car("Fred", 30, 0);

public IEnumerator GetEnumerator()

// Return the array object's IEnumerator.

return carArray.GetEnumerator();

  • Once you have updated your Garage type, you can now safely use the type within the C# foreach

construct.

  • Furthermore, given that the GetEnumerator() method has been defined publicly, the object user

could also interact with the IEnumerator type:

// Manually work with IEnumerator.

IEnumerator i = carLot.GetEnumerator();

i.MoveNext();

Car myCar = (Car)i.Current;

Console.WriteLine("{0} is going {1} MPH", myCar.PetName, myCar.CurrSpeed);

  • If you would prefer to hide the functionality of IEnumerable from the object level, simply make use

of explicit interface implementation:

public IEnumerator IEnumerable.GetEnumerator()

// Return the array object's IEnumerator.

return carArray.GetEnumerator();

Understanding C# Iterator Methods

  • An iterator is a member that specifies how a container’s internal items should be returned when

processed by foreach.

  • While the iterator method must still be named GetEnumerator(), and the return value must still be

of type IEnumerator, your custom class does not need to implement any of the expected interfaces:

public class Garage // No longer implementing IEnumerable!

private Car[] carArray;

// Iterator method.

public IEnumerator GetEnumerator()

foreach (Car c in carArray)

yield return c;

  • Notice that this implementation of GetEnumerator() iterates over the subitems using internal foreach

logic and returns each Car to the caller using the new yield return syntax.

  • The yield keyword is used to specify the value (or values) to be returned to the caller’s foreach

construct.

  • When the yield return statement is reached, the current location is stored, and execution is restarted

from this location the next time the iterator is called.

  • When the C# compiler encounters an iterator method, it will dynamically generate a nested class

within the scope of the defining type (Garage in this case). The autogenerated class implements the

GetEnumerator(), MoveNext() and Current members on your behalf (oddly, the Reset() method is

not, and you will receive a runtime exception if you attempt to call it).

public interface ICloneable

  • System.Object defines a member named MemberwiseClone(). This method is used to obtain a

shallow copy of the current object.

  • Object users do not call this method directly (as it is protected); however, a given object may call this

method itself during the cloning process. To illustrate, assume you have a class named Point:

// A class named Point.

public class Point

// Public for easy access.

public int x, y;

public Point(int x, int y) { this.x = x; this.y = y;}

public Point(){}

// Override Object.ToString().

public override string ToString()

{ return string.Format("X = {0}; Y = {1}", x, y ); }

static void Main(string[] args)

// Two references to same object!

Point p1 = new Point(50, 50);

Point p2 = p1;

p2.x = 0;

Console.WriteLine(p1);

Console.WriteLine(p2);

  • When you wish to equip your custom types to support the ability to return an identical copy of itself

to the caller, you may implement the standard ICloneable interface.

  • This type defines a single method named Clone():

public interface ICloneable

object Clone();

  • Obviously, the implementation of the Clone() method varies between objects. However, the basic

functionality tends to be the same: Copy the values of your member variables into a new

objectinstance, and return it to the user.

  • To illustrate, ponder the following update to the Point class:

// The Point now supports "clone-ability."

public class Point : ICloneable

public int x, y;

public Point(){ }

public Point(int x, int y) { this.x = x; this.y = y;}

// Return a copy of the current object.

public object Clone()

{ return new Point(this.x, this.y); }

public override string ToString()

{ return string.Format("X = {0}; Y = {1}", x, y ); }

  • In this way, you can create exact stand-alone copies of the Point type, as illustrated by the following

code:

static void Main(string[] args)

// Notice Clone() returns a generic object type.

// You must perform an explicit cast to obtain the derived type.

Point p3 = new Point(100, 100);

Point p4 = (Point)p3.Clone();

// Change p4.x (which will not change p3.x).

p4.x = 0;

// Print each object.

Console.WriteLine(p3);

Console.WriteLine(p4);

  • Because the Point type does not contain reference type variables, you could simplify the

implementation of the Clone() method as follows:

public object Clone()

// Copy each field of the Point member by member.

return this.MemberwiseClone();

A More Elaborate Cloning Example

// This class describes a point.

public class PointDescription

// Exposed publicly for simplicity.

public string petName;

public Guid pointID;

public PointDescription()

this.petName = "No-name";

pointID = Guid.NewGuid();

public class Point : ICloneable

public int x, y;

return newPoint;

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 CompareTo(object o);

Example:

public class Car

private int carID;

public int ID

get { return carID; }

set { carID = value; }

public Car(string name, int currSp, int id)

currSpeed = currSp;

petName = name;

carID = id;

static void Main(string[] args)

// Make an array of Car types.

Car[] myAutos = new Car[5];

myAutos[0] = new Car("Rusty", 80, 1);

myAutos[1] = new Car("Mary", 40, 234);

myAutos[2] = new Car("Viper", 40, 34);

myAutos[3] = new Car("Mel", 40, 4);

myAutos[4] = new Car("Chucky", 40, 5);

CompareTo()

// The iteration of the Car can be ordered

// based on the CarID.

public class Car : IComparable

// IComparable implementation.

int IComparable.CompareTo(object obj)

Car temp = (Car)obj;

if(this.carID > temp.carID)

return 1;

if(this.carID < temp.carID)

return - 1;

else

return 0;

static void Main(string[] args)

// Make an array of Car types.

// Dump current array.

Console.WriteLine("Here is the unordered set of cars:");

foreach(Car c in myAutos)

Console.WriteLine("{0} {1}", c.ID, c.PetName);

// Now, sort them using IComparable!

Array.Sort(myAutos);

// Dump sorted array.

Console.WriteLine("Here is the ordered set of cars:");

foreach(Car c in myAutos)

Console.WriteLine("{0} {1}", c.ID, c.PetName);

  • Console.ReadLine();

Output: