You are on page 1of 15

Topics on Enterprise Architecture 2 [10MCA53]

UNIT VI
Interfaces and Collections
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 implement.
Unlike other .NET types, interfaces never specify a base class and contain members that do not
take an access modifier.
To begin, create a brand-new Console Application named user_interface.
Using the Project ->Add Existing Item menu option, insert an interface to the project.
An interface is defined using the C# interface keyword.
Unlike other .NET types, interfaces never specify a base class (not even System.Object) and
their members never specify an access modifier (as all interface members are implicitly public
and abstract).
To get the ball rolling, here is a custom interface defined in C#:
public interface IPoints
{
int points();
}
Notice that when we define interface members, we do not define an implementation scope for
the member in question.
.NET interface types are also able to define any number of property prototypes.
Implementing an Interface
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.
namespaceuser_interface
{

publicclassshapes
{
protectedvoiddisplay()
{
Console.WriteLine("Allareshapes");
}
}
publicclasssquare:shapes,IPoints
{
publicintpoints()
{
return4;
}
publicvoidprint()
{
base.display();
Console.WriteLine("Square");
}

Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

Topics on Enterprise Architecture 2 [10MCA53]


}
publicclasstriangle:shapes,IPoints
{
publicintpoints()
{
return3;
}
publicvoidprint()
{
base.display();
Console.WriteLine("Triangle");
}
}
publicclasscircle:shapes
{
publicvoidprint()
{
base.display();
Console.WriteLine("Circle");
}
}
classProgram
{
staticvoidMain(string[]args)
{
squares1=newsquare();
s1.print();
Console.WriteLine("Noofpoints={0}",s1.points());
trianglet1=newtriangle();
t1.print();
Console.WriteLine("Noofpoints={0}",t1.points());

circlec1=newcircle();
c1.print();
Console.Read();
}
}
}

Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

Topics on Enterprise Architecture 2 [10MCA53]

Difference between Interfaces and Abstract classes


A class can implement any number of interfaces but a subclass can at most use only one
abstract class.
A class type does define a set of abstract members, it is also free to define any number of
constructors, field data, non abstract members (with implementation), and so on. Interfaces, on
the other hand, only contain abstract members.
An abstract class can declare or use any variables while an interface is not allowed to do so.
An abstract Class is allowed to have all access modifiers for all of its member declaration
while in interface we can not declare any access modifier(including public) as all the members
of interface are implicitly public.
Abstract parent class suffers from one major limitation in that only derived types support the
members defined by the abstract parent.
Another limitation of traditional abstract base classes is that each and every derived type must
contend with the set of abstract members and provide an implementation.

Invoking Interface members at the Object Level


staticvoidMain(string[]args)
{
squares1=newsquare();
s1.print();
Console.WriteLine("Noofpoints={0}",s1.points());
trianglet1=newtriangle();
t1.print();
Console.WriteLine("Noofpoints={0}",t1.points());
circlec1=newcircle();
c1.print();
Console.Read();
}

This approach works fine in this particular case, given that we are well aware that the square
type has implemented the interface in question and therefore has a Points property.
Obtaining Interface References: Explicit Casting
Other times, however, we may not be able to determine which interfaces are supported by a
given type.
If we attempt to invoke the Points property on a type that has not implemented IPoints, we
receive an error.
Next question: how can we dynamically determine the set of interfaces supported by a type?
One way to determine at runtime whether a type supports a specific interface is to make use of
an explicit cast.
If the type does not support the requested interface, we receive an InvalidCastException.
To handle this possibility gracefully, make use of structured exception handling, for example:
try
{
circlec1=newcircle();
c1.print();
/*IPointsip=(IPoints)c1;
Console.WriteLine(ip.points());*/
Console.WriteLine(((IPoints)c1).points());
}

Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

Topics on Enterprise Architecture 2 [10MCA53]


catch(InvalidCastExceptione)
{
Console.WriteLine("NotimplementedIPointsinterface");
Console.WriteLine(e.Message);
}

Obtaining Interface References: The as keyword


The second way you can determine whether a given type supports an interface is to make use
of the as keyword.
If the object can be treated as the specified interface, we are returned a reference to the
interface in question. If not, we receive a null reference.
staticvoidMain(string[]args)
{

circlec1=newcircle();
c1.print();
IPointsip=c1asIPoints;
if(ip!=null)
Console.WriteLine(ip.points());
else
Console.WriteLine("IPointsinterfacenotimplemented");
}

Obtaining Interface References: The is keyword


You may also check for an implemented interface using the is keyword.
If the object in question is not compatible with the specified interface, we are returned the
value false.
staticvoidMain(string[]args)
{

circlec1=newcircle();
c1.print();
if(c1isIPoints)
Console.WriteLine(c1.points());
else
Console.WriteLine("IPointsinterfaceisnotused");

Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

Topics on Enterprise Architecture 2 [10MCA53]

Interfaces as Parameters
Given that interfaces are valid .NET types, we may construct methods that take interfaces as
Parameters.
namespaceinterface_param
{

interfaceIPrint
{
voidprint();
}
publicclasssquare:IPrint
{
publicvoidprint()
{
Console.WriteLine("Square");
}
}
publicclasstriangle:IPrint
{
publicvoidprint()
{
Console.WriteLine("Triangle");
}
}
classProgram
{
publicstaticvoiddisplay(IPrintip)
{
Console.WriteLine("PrintingIPrint");
ip.print();
}
staticvoidMain(string[]args)
{
squares1=newsquare();
if(s1isIPrint)
display((IPrint)s1);
Console.Read();
}
}
}

Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

Topics on Enterprise Architecture 2 [10MCA53]

Building Interface hierarchies


Interfaces can be arranged into an interface hierarchy.
Like a class hierarchy, when an interface extends an existing interface, it inherits the abstract
members defined by the parent type(s).
Of course, unlike class-based inheritance, derived interfaces never inherit true implementation.
Rather, a derived interface simply extends its own definition with additional abstract members.
The topmost interface defines a general behavior, while the most derived interface defines
more specific behaviors.
namespaceinterface_hierarchy
{

interfacelibrary
{
voiddisp_lib();
}
interfacereference:library
{
voiddisp_ref();
}
interfacejournal:reference
{
voiddisp_jour();
}
publicclassbooks:journal
{
publicvoiddisp_lib()
{
Console.WriteLine("CollegeLibrary");
}
publicvoiddisp_ref()
{
Console.WriteLine("ReferenceSectioninLibrary");
}
publicvoiddisp_jour()
{
Console.WriteLine("JournalSectioninReference");
}
}
classProgram
{
staticvoidMain(string[]args)
{
booksb1=newbooks();
b1.disp_lib();
b1.disp_ref();
b1.disp_jour();
Console.Read();
}
}
}

Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

Topics on Enterprise Architecture 2 [10MCA53]

Interfaces with Multiple Base Interfaces


It is possible for a single interface to extend multiple base interfaces.
It is not possible to build a class that derives from multiple base classes.
namespaceinterface_multiple
{

interfaceIBasicCar
{
voidDrive();
}
interfaceIUnderWaterCar
{
voidDive();
}
interfaceICar007:IBasicCar,IUnderWaterCar
{
voidSuper();
}
publicclassBond:ICar007
{
voidIBasicCar.Drive()
{
Console.WriteLine("Speedingup...");
}
voidIUnderWaterCar.Dive()
{
Console.WriteLine("Submering...");
}

Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

Topics on Enterprise Architecture 2 [10MCA53]


voidICar007.Super()
{
Console.WriteLine("007");
}
}
classProgram
{
staticvoidMain(string[]args)
{
Bondj=newBond();
if(jisICar007)
{
((ICar007)j).Drive();
((ICar007)j).Dive();
((ICar007)j).Super();
}
Console.Read();
}
}
}

Understanding the IConvertible Interface


IConvertible interface allows us to dynamically convert between data types using interfacebased programming techniques.
This interface defines a number of methods of the form ToXXXX(), which provide a way to
convert from one type into another.
The IConvertible interface is used by the .NET Convert class to return the specified type value
of the object.
The IConvertible interface has 17 methods, all of which must be overridden to provide type
conversions for objects value or reference.
These methods are GetTypeCode, ToBoolean, ToSByte, ToByte, ToInt16, ToUInt16,
ToInt32, ToUInt32, ToInt64, ToUInt64, ToSingle, ToDouble, ToDecimal, ToDateTime,
ToChar, ToString, and ToType.
Each of these methods will contain the code implementing the conversion of the specific data
type, or will throw an InvalidCastException to indicate that no such conversion exists.
Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

Topics on Enterprise Architecture 2 [10MCA53]


public interface IConvertible
{
publicTypeCodeGetTypeCode();
boolIConvertible.ToBoolean(IFormatProviderprovider);
byteIConvertible.ToByte(IFormatProviderprovider);
charIConvertible.ToChar(IFormatProviderprovider)
DateTimeIConvertible.ToDateTime(IFormatProviderprovider);
decimalIConvertible.ToDecimal(IFormatProviderprovider);
doubleIConvertible.ToDouble(IFormatProviderprovider);
shortIConvertible.ToInt16(IFormatProviderprovider);
intIConvertible.ToInt32(IFormatProviderprovider);
longIConvertible.ToInt64(IFormatProviderprovider);
sbyteIConvertible.ToSByte(IFormatProviderprovider);
floatIConvertible.ToSingle(IFormatProviderprovider);
stringIConvertible.ToString(IFormatProviderprovider);
objectIConvertible.ToType(TypeconversionType,IFormatProviderprovider);
UInt16IConvertible.ToUInt16(IFormatProviderprovider);
UInt32IConvertible.ToUInt32(IFormatProviderprovider);
UInt64IConvertible.ToUInt64(IFormatProviderprovider);
}

IFormatProvider
All the ToXXX() methods take a parameter of type IFormatProvider.
Objects that implement this interface are able to format their contents based on culture-specific
information.
public interface IFormatProvider
{
object GetFormat(Type formattype);
}
IConvertible.GetTypeCode
In addition to ToXXXX() members, IConvertible defines a member named GetTypeCode().
This method allows to discover the value that represents the type code of type.
The System.Convert type
The System namespace defines a type named Convert, which echoes the functionality of the
IConvertible interface.
The same set of members is defined in System.Convert.

Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

Topics on Enterprise Architecture 2 [10MCA53]

Building Cloneable Objects (ICloneable)


The System.ICloneable interface defines a method of cloningcopyingto create a new
instance of a class with the identical value as an existing instance.
There are two ways to clone an instance:
1. Shallow copy - may be linked to data shared by both the original and the copy
2. Deep copy - contains the complete encapsulated data of the original object
A shallow copy is by far the easiest way to clone your class. This can be achieved with the
MemberwiseClone method inherited by all classes from Object.
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, we have a simple class named Point:
namespaceclone
{

publicclassPoint
{
//Publicforeasyaccess.
publicintx,y;
publicPoint(intx,inty){this.x=x;this.y=y;}
publicPoint(){}
//OverrideObject.ToString().
publicoverridestringToString()
{returnstring.Format("X={0};Y={1}",x,y);}
}
classProgram
{
staticvoidMain(string[]args)
{
Console.WriteLine("*****FunwithObjectCloning*****\n");
//Tworeferencestosameobject!
Pointp1=newPoint(50,50);
Pointp2=p1;
p2.x=0;
Console.WriteLine(p1);
Console.WriteLine(p2);
Console.ReadLine();
}
}
}

***** Fun with Object Cloning *****


X = 0; Y = 50
X = 0; Y = 50
If we assign one reference variable to another, we have two references pointing to the same
object in memory.
Thus, the following assignment operation results in two references to the same Point object on
the heap; modifications using either reference affect the same object on the heap.
When we wish to equip our custom types to support the ability to return an identical copy of
itself to the caller, we may implement the standard ICloneable interface.
This type defines a single method named Clone():
Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

Topics on Enterprise Architecture 2 [10MCA53]


public interface ICloneable
{
object Clone();
}
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 object instance of the same type, and return it to the user.
To illustrate, ponder the following update to the Point class:
namespaceclone
{

publicclassPoint:ICloneable
{
publicintx,y;
publicPoint(){}
publicPoint(intx,inty){this.x=x;this.y=y;}
//Returnacopyofthecurrentobject.
publicobjectClone()
{returnnewPoint(this.x,this.y);}
publicoverridestringToString()
{returnstring.Format("X={0};Y={1}",x,y);}
}
classProgram
{
staticvoidMain(string[]args)
{
Console.WriteLine("*****FunwithObjectCloning*****\n");
//NoticeClone()returnsagenericobjecttype.
//Youmustperformanexplicitcasttoobtainthederivedtype.
Pointp3=newPoint(100,100);
Pointp4=(Point)p3.Clone();
//Changep4.x(whichwillnotchangep3.x).
p4.x=0;
//Printeachobject.
Console.WriteLine(p3);
Console.WriteLine(p4);
Console.ReadLine();
}
}
}

***** Fun with Object Cloning *****


X = 100; Y = 100
X = 0; Y = 100

Building Comparable Objects (IComparable)


The System.Collection namespace provides us two built in interfaces witch are IComparable
and IComparer interfaces.
The first one, namely, the IComparable specifies a behavior that allows an object to be
compared to another one from the same type according to a specified member value.
At the other hand, IComparer interface enables us to specify multiple sort orders.

Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

Topics on Enterprise Architecture 2 [10MCA53]

IComparable
The role of IComparable is to provide a method of comparing two objects of a particular type.
This is necessary if you want to provide any ordering capability for your object. Think of
IComparable as providing a default sort order for your objects. For example, if you have an
array of objects of your type, and you call the
Sort method on that array, IComparable
provides the comparison of objects during the sort. When you implement the IComparable
interface, you must implement the CompareTo method.
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);
}
When we build custom types, we can implement IComparable to allow arrays of our types to
be sorted.
When we flesh out the details of CompareTo(), it will be up to the user to decide what the
baseline of the ordering operation will be.
For the Car type, the internal carID seems to be the logical candidate.
The logic behind CompareTo() is to test the incoming type against the current instance based
on a specific point of data.
The return value of CompareTo() is used to discover whether this type is less than, greater
than, or equal to.
Table 9-1. CompareTo() Return Values

CompareTo() Return
Value
Any number less than zero
Zero
Any number greater than zero

Meaning in Life
This instance comes before the specified object in the sort order.
This instance is equal to the specified object.
This instance comes after the specified object in the sort order.

namespacecompare
{

publicclassCar:IComparable
{
privateintcarID;
privatestringpetName;
publicintID
{
get{returncarID;}
set{carID=value;}
}
publicCar(stringname,intid)
{
petName=name;
carID=id;
}
publicvoidprint()

Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

Topics on Enterprise Architecture 2 [10MCA53]


{
Console.WriteLine("PetName:{0}",petName);
Console.WriteLine("ID:{0}",carID);
}
intIComparable.CompareTo(objectobj)
{
Cartemp=(Car)obj;
returnthis.carID.CompareTo(temp.carID);
}
}
classProgram
{
staticvoidMain(string[]args)
{
Console.WriteLine("*****FunwithObjectSorting*****\n");
//MakeanarrayofCartypes.
Car[]myAutos=newCar[5];
myAutos[0]=newCar("Rusty",1);
myAutos[1]=newCar("Mary",234);
myAutos[2]=newCar("Viper",34);
myAutos[3]=newCar("Mel",4);
myAutos[4]=newCar("Chucky",5);
//Printthearray
for(inti=0;i<myAutos.Length;i++)
myAutos[i].print();
//Sortthearrayofobjects
Array.Sort(myAutos);
//Printaftersorting
Console.WriteLine("*****AfterObjectsSorting*****\n");
for(inti=0;i<myAutos.Length;i++)
myAutos[i].print();
Console.ReadLine();
}
}
}

***** Fun with Object Sorting *****


PetName:Rusty
ID: 1
PetName:Mary
ID: 234
PetName:Viper
ID: 34
PetName:Mel
ID: 4
PetName:Chucky
ID: 5
***** After Objects Sorting *****
PetName:Rusty
ID: 1
PetName:Mel
ID: 4
Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

Topics on Enterprise Architecture 2 [10MCA53]


PetName:Chucky
ID: 5
PetName:Viper
ID: 34
PetName:Mary
ID: 234

IComparer
The role of IComparer is to provide additional comparison mechanisms. For example, you
may want to provide ordering of your class on several fields or properties, ascending and
descending order on the same field, or both.

Using IComparer is a two-step process. First, declare a class that implements

IComparer,

and then implement the Compare method.


What if you wanted to build a Car that could be sorted by ID as well as by pet name?
you need to make friends with another standard interface named IComparer, defined within the
System.Collections namespace as follows:
// A generic way to compare two objects.
interface IComparer
{
int Compare(object o1, object o2);
}
Unlike the IComparable interface, IComparer is typically not implemented on the type you are
trying to sort (i.e., the Car). Rather, you implement this interface on any number of helper
classes, one for each sort order (pet name, car ID, etc.).
// This helper class is used to sort an array of Cars by pet name.
using System.Collections;
public class PetNameComparer : IComparer
{
// Test the pet name of each object.
int IComparer.Compare(object o1, object o2)
{
Car t1 = (Car)o1;
Car t2 = (Car)o2;
return String.Compare(t1.PetName, t2.PetName);
}
}
The object user code is able to make use of this helper class.
System.Array has a number of overloaded Sort() methods, one that just happens to take an
object implementing IComparer.
static void Main(string[] args)
{
...
Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

Topics on Enterprise Architecture 2 [10MCA53]


// Now sort by pet name.
Array.Sort(myAutos, new PetNameComparer());
// Dump sorted array.
Console.WriteLine("Ordering by pet name:");
foreach(Car c in myAutos)
Console.WriteLine("{0} {1}", c.ID, c.PetName);
...
}

Custom Properties, Custom Sort Types


We can make use of a custom static property in order to help the object user along when
sorting our Car types by a specific data point.
Assume the Car class has added a static read-only property named SortByPetName that returns
an instance of an object implementing the IComparer interface (PetNameComparer, in this
case):
// We now support a custom property to return
// the correct IComparer interface.
public class Car : IComparable
{
...
// Property to return the SortByPetName comparer.
public static IComparer SortByPetName
{ get { return (IComparer)new PetNameComparer(); } }
}
The object user code can now sort by pet name using a strongly associated property, rather than
just having to know to use the stand-alone PetNameComparer class type:
// Sorting by pet name made a bit cleaner.
Array.Sort(myAutos, Car.SortByPetName);

Mrs. R.Ushasree
Asst Prof of M. C. A.,
TOCE

You might also like