Unit 4: Interfaces, Collections, Delegates & Events 1 Prof. Sushant S.Sundikar C# Programming Unit 4: Interfaces, Collections, Delegates & Events . Defining Interfaces in C# An interface is nothing more than 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. Interfaces are declared by using the interface keyword. Here is a simplified form of an interface declaration: interface name { ret-type method-name1(param-list); ret-type method-name2(param-list); // ... ret-type method-nameN(param-list); } The name of the interface is specified by name. Methods are declared using only their return type and signature. They are, essentially, abstract methods. As explained, in an interface, no method can have an implementation. Thus, each class that includes an interface must implement all of the methods. In an interface, methods are implicitly public, and no explicit access specifier is allowed. Here is an example of an interface. It specifies the interface to a class that generates a series of numbers. public interface ISeries { int GetNext(); // return next number in series void Reset(); // restart void SetStart(int x); // set starting value } Program ch04pg01.cs: Program to demonstrate the use of interfaces Implementing an Interface in C# Once an interface has been defined, one or more classes can implement that interface. To implement an interface, the name of the interface is specified after the class name in just the same way that a base class is specified. The general form of a class that implements an interface is shown here: class class-name : interface-name {
24
Embed
Unit 4: Interfaces, Collections, Delegates & Events · 2013. 9. 19. · Unit 4: Interfaces, Collections, Delegates & Events 10 Prof. Sushant S.Sundikar C# Programming carArray[3]
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Unit 4: Interfaces, Collections, Delegates & Events 1
Prof. Sushant S.Sundikar C# Programming
Unit 4: Interfaces, Collections, Delegates & Events .
Defining Interfaces in C#
An interface is nothing more than 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. Interfaces are declared
by using the interface keyword. Here is a simplified form of an interface declaration:
interface name {
ret-type method-name1(param-list);
ret-type method-name2(param-list);
// ...
ret-type method-nameN(param-list);
}
The name of the interface is specified by name. Methods are declared using only their return type
and signature. They are, essentially, abstract methods. As explained, in an interface, no method can
have an implementation. Thus, each class that includes an interface must implement all of the
methods. In an interface, methods are implicitly public, and no explicit access specifier is allowed.
Here is an example of an interface. It specifies the interface to a class that generates a series of
numbers.
public interface ISeries {
int GetNext(); // return next number in series
void Reset(); // restart
void SetStart(int x); // set starting value
}
Program ch04pg01.cs: Program to demonstrate the use of interfaces
Implementing an Interface in C#
Once an interface has been defined, one or more classes can implement that interface. To
implement an interface, the name of the interface is specified after the class name in just the same
way that a base class is specified. The general form of a class that implements an interface is shown
here:
class class-name : interface-name {
Unit 4: Interfaces, Collections, Delegates & Events 2
Prof. Sushant S.Sundikar C# Programming
// class-body
}
The name of the interface being implemented is specified in interface-name. When a class
implements an interface, the class must implement the entire interface. It cannot pick and choose
which parts to implement.
A class can implement more than one interface. When a class implements more than one interface,
specify each interface in a comma-separated list. A class can inherit a base class and also implement
one or more interfaces. In this case, the name of the base class must come first in the comma-
separated list.
Here is an example that implements the ISeries interface shown earlier.
// Implement ISeries.
class ByTwos : ISeries
{… }
Example 2: class AnotherClass derives from a custom base class MyBaseClass and implements a
single interface ISomeInterface.
public class AnotherClass : MyBaseClass, ISomeInterface
{...}
Contrasting Interfaces to Abstract Base Classes C# allows you to build abstract class types containing abstract methods. However, abstract base
classes do far more than define a group of abstract methods. They 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.
Interfaces, on the other hand, are pure protocol. Interfaces never define state data and never
provide an implementation of the methods (if you try, you receive a compile-time error):
public interface IAmABadInterface
{
// Error, interfaces can't define data!
int myInt = 0;
// Error, only abstract members allowed!
void MyMethod()
{ Console.WriteLine("Eek!"); }
}
Unit 4: Interfaces, Collections, Delegates & Events 3
Prof. Sushant S.Sundikar C# Programming
Interface types are also quite helpful given that C# (and .NET-aware languages in general) only
support single inheritance; the interface-based protocol allows a given type to support numerous
behaviors, while avoiding the issues that arise when deriving from extending multiple base classes.
Most importantly, interface-based programming provides yet another way to inject polymorphic
behavior into a system. If multiple classes (or structures) implement the same interface in their
unique ways, you have the power to treat each type in the same manner.
Invoking Interface Members at the Object Level
Assume that we have an interface called IPointy
// Interface IPointy has as a read-only property.
public interface IPointy
{ byte Points{get;} }
And a set of types that support IPointy Interface,
// 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; }
}
}
The next question is how you interact with the new functionality. 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();
}
Unit 4: Interfaces, Collections, Delegates & Events 4
Prof. Sushant S.Sundikar C# Programming
This approach works fine, 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.
To dynamically determine the set of interfaces supported by a type do the following:
• The first way you can determine at runtime if a type supports a specific interface is to make
use of an explicit cast. If the type does not support the requested interface, you receive an
InvalidCastException. To handle this possibility gracefully, make use of structured exception
handling, for example:
// Catch a possible InvalidCastException.
Circle c = new Circle("Lisa");
IPointy itfPt;
try
{
itfPt = (IPointy)c;
Console.WriteLine(itfPt.Points);
}
catch (InvalidCastException e)
{ Console.WriteLine(e.Message); }
• 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, you are
returned a reference to the interface in question. If not, you receive a null reference:
// Can we treat hex2 as IPointy?
Hexagon hex2 = new Hexagon("Peter");
IPointy itfPt2 = hex2 as IPointy;
if(itfPt2 != null)
Console.WriteLine("Points: {0}", itfPt2.Points);
else
Console.WriteLine("OOPS! Not pointy...");
• You may also check for an implemented interface using the is keyword. If the object in
question is not compatible with the specified interface, you are returned the value false. On
the other hand, if the type is compatible with the interface in question, you can safely call
the members without needing to make use of try/catch logic.
Shape[] s = { new Hexagon(), new Circle(), new
Triangle("Joe"), new Circle("JoJo")} ;
for(int i = 0; i < s.Length; i++)
Unit 4: Interfaces, Collections, Delegates & Events 5
Prof. Sushant S.Sundikar C# Programming
{
// Recall the Shape base class defines an abstract Draw()
// member, so all shapes know how to draw themselves.
For example, assume you wish to build a delegate named BinaryOp that can point to any method
that returns an integer and takes two integers as input parameters:
// This delegate can point to any method, taking two integers and returning an integer.
public delegate int BinaryOp(int x, int y);
When the C# compiler processes delegate types, it automatically generates a sealed class deriving
from System.MulticastDelegate. This class provides the necessary infrastructure for the delegate to
hold onto the list of methods to be invoked at a later time.
As you can see, the generated BinaryOp class defines three public methods. Invoke() is perhaps the
core method, as it is used to invoke each method maintained by the delegate type in a synchronous
manner, meaning the caller must wait for the call to complete before continuing on its way.
BeginInvoke() and EndInvoke() provide the ability to call the current method asynchronously on a
second thread of execution.
Unit 4: Interfaces, Collections, Delegates & Events 17
Prof. Sushant S.Sundikar C# Programming
Now, how exactly does the compiler know how to define the Invoke(), BeginInvoke(), and
EndInvoke() methods? To understand the process, here is the crux of the generated BinaryOp class
type (bold marks the items specified by the defined delegate type):
sealed class BinaryOp : System.MulticastDelegate {
public BinaryOp(object target, uint functionAddress); public int Invoke(int x, int y); public IAsyncResult BeginInvoke(int x, int y, AsyncCallback cb, object state);
public int EndInvoke(IAsyncResult result);
}
First, notice that the parameters and return value defined for the Invoke() method exactly match the
definition of the BinaryOp delegate. The initial parameters to BeginInvoke() members (two integers
in our case) are also based on the BinaryOp delegate. Finally, the return value of EndInvoke() is
identical to the original delegate declaration.
To summarize, a C# delegate definition results in a sealed class with three compiler-generated
methods whose parameter and return types are based on the delegate’s declaration.
The System.MulticastDelegate and System. Delegate Base Classes
So, when you build a type using the C# delegate keyword, you indirectly declare a class type that
derives from System.MulticastDelegate. This class provides descendents with access to a list that
contains the addresses of the methods maintained by the delegate type, as well as several additional
methods (and a few overloaded operators) to interact with the invocation list. Here are the Select
Members of System.MultcastDelegate/System.Delegate
Inherited Member Meaning in Life
Method This property returns a System.Reflection.MethodInfo type
thatrepresents details of a static method that is maintained by the
delegate.
Target If the method to be called is defined at the object level (rather than a
staticmethod), Target returns an object that represents the method
maintained by the delegate. If the value returned from Target equals
null, the method to be called is a static member.
Combine() This static method adds a method to the list maintained by the
delegate.In C#, you trigger this method using the overloaded +=
operator as a shorthand notation.
GetInvocationList() This method returns an array of System.Delegate types, each
representing a particular method that may be invoked.
Remove() These static methods removes a method (or all methods) from the
RemoveAll() invocation list. In C#, the Remove() method can be called indirectly
usingthe overloaded -= operator.
Unit 4: Interfaces, Collections, Delegates & Events 18
Prof. Sushant S.Sundikar C# Programming
The Simplest Possible Delegate Example
Program ch04pg06.cs: Program to demonstrate use of delegates
using System;
// This delegate can point to any method,
// taking two integers and returning an
// integer.
public delegate int BinaryOp(int x, int y);
// This class contains methods BinaryOp will
// point to.
public class SimpleMath
{
public static int Add(int x, int y)
{ return x + y; }
public static int Subtract(int x, int y)
{ return x – y; }
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("***** Simple Delegate Example *****\n");
// Create a BinaryOp object that
// "points to" SimpleMath.Add().
BinaryOp b = new BinaryOp(SimpleMath.Add);
b+=SimpleMath.Sub;
// Invoke Add() method using delegate.
Console.WriteLine("10 + 10 is {0}", b(10, 10));
Console.ReadLine();
}
}
Multicasting
One of the most exciting features of a delegate is its support for multicasting. In simple terms,
multicasting is the ability to create an invocation list, or chain, of methods that will be automatically
called when a delegate is invoked. Such a chain is very easy to create. Simply instantiate a delegate,
and then use the + or += operator to add methods to the chain. To remove a method, use – or – =.
If the delegate returns a value, then the value returned by the last method in the list becomes the
return value of the entire delegate invocation. Thus, a delegate that makes use of multicasting will
often have a void return type.
Program ch04pg07.cs: Program to demonstrate multicasting of delegates
using System;
// Define a custom delegate that has a string parameter and returns void.
Unit 4: Interfaces, Collections, Delegates & Events 19
Prof. Sushant S.Sundikar C# Programming
delegate void CustomDel(string s);
class TestClass
{
// Define two methods that have the same signature as CustomDel.