www.itu.dk
Advanced C#, part I
Niels HallenbergIT University of Copenhagen
BAAAP – Spring 2009
www.itu.dk
Outline
Advanced C#, Part I• Interfaces• Collections and Generics• Delegates and Lanbdas
For our project• High Quality Test Data• Stubs
www.itu.dk
Interfaces
– Interfaces and Abstract Base Classes
– What are Interfaces used for?• You have a single hierarchy where
only a subset of the derived types have a common behavior
• The same behavior must be implemented on types in different hierarchies with only the System.object as common parent class.
Why do we need both?
Functionality that must be supported
by some type.
You can’t enable four-wheel drive
on all cars.
Illustrated by many built in interfaces, fx
IEnumerable, IEnumerator, ICloneable,
ICompareable and IComparer
www.itu.dk
Single Hierarky Interface• Abstract Vechicle class
public abstract class Vechicle { int numWheels; String vechicleName;
public Vechicle(int w, String n) { this.numWheels = w; this.vechicleName = n; }
public override String ToString() { return "Vechicle " + this.vechicleName + …; } public abstract int numPersons();} All sub classes must
have a numPersons method.
www.itu.dk
Single Hierarky Interface• The ILicenseNo interface
public interface ILicenseNo { String LicenseNo {get; set;}}
• Some vechicles does have a license number
www.itu.dk
Single Hierarky Interface• Cycle, Bike and Car classes
public class Cycle : Vechicle { public Cycle() : base(2, "cycle") { } public override int numPersons() { return 1; }}
public class Bike : Vechicle, ILicenseNo { private String licenseNo; public Bike(String licenseNo) : base(2, "bike") { this.licenseNo = licenseNo; } public String LicenseNo { get { return this.licenseNo; } set { this.licenseNo = value; } } public override int numPersons() { return 2; }}
It’s a sports cycle.
A Bike does have a license number
Required by the interface
Required by the Vechicle class
www.itu.dk
Single Hierarky Interface• The Car class
public class Car : Vechicle, ILicenseNo { String licenseNo; public Car(String licenseNo) : base(4, "car") { this.licenseNo = licenseNo; } public String LicenseNo { get { return this.licenseNo; } set { this.licenseNo = value; } } public override int numPersons() { return 4; }}
A car does have a license number
www.itu.dk
Single Hierarky Interface• Using the class hierarky
Vechicle[] vs = { new Cycle(), new Bike("RX 34213"), new Car("GC 45221") };
// Print all vechiclesforeach (Vechicle v in vs) Console.WriteLine(v.ToString() + " has " + v.numPersons() + " seats.");
A bike and Car got a license number
All vechicles can be pretty printed and got a
number of persons.
All sub-classes to Vechicle must implement numPersons.
• Using is and as.
Console.WriteLine("--- License Numbers ---");foreach (Vechicle v in vs) if (v is ILicenseNo) Console.WriteLine(v.ToString() + " has license number: " + (v as ILicenseNo).LicenseNo);
Test for class type
Type cast
www.itu.dk
Single Hierarky Interface• Invalid Cast Exception
Console.WriteLine("--- Invalid Cast Exception ---");// Mk. array of vechicles with license numbertry { ILicenseNo[] xs = { (ILicenseNo)vs[0], (ILicenseNo)vs[1], (ILicenseNo)vs[2] };} catch (InvalidCastException e) { Console.WriteLine("Not all vechicles has a license no.");}
A Cycle class does not implement ILicenseNo.
Example file: SingleHierarkyInterface
www.itu.dk
Explicit Named Interface• Same method name in a class and interface • Same method name in two or more interfaces. This require
Multiple Interface support.
// Interface for vechicles having an extra seats that can // be added, fx a side car on a Bike and a Cycle.public interface ISideCar { int numPersons();}
Return number of persons in side car.
• The Cycle and Bike class may have a side car.
public class Bike : Vechicle, ILicenseNo, ISideCar { … public override int numPersons() { return 2; } // There are room for one child or adult. int ISideCar.numPersons() { return 1; }}
numPersons required by abstract Vechicle
class
numPersons required by the side car
interface.
Example file: ExplicitlyNamedInterface
www.itu.dk
Explicit Named Interface• A cycle can have two kids in a side car.
public class Cycle : Vechicle, ISideCar { public Cycle() : base(2, "cycle") { } public override int numPersons() { return 1; } // There are room for two kids. int ISideCar.numPersons() { return 2; }}
Return number of persons in side car.
www.itu.dk
Explicit Named Interface• What version of numPersons is used below.
Vechicle[] vs = { new Cycle(), new Bike("RX 34213"), new Car("GC 45221") };
// Print vechicles with num persons – // side cars are not included.foreach (Vechicle v in vs) Console.WriteLine(v.ToString() + " has " + v.numPersons() + " seats.");
• The Cycle and Bike class may have a side car.
The numPersons method from the
abstract class Vechicle
foreach (Vechicle v in vs) if (v is ISideCar) Console.WriteLine(v.ToString() + " has " + ((v as ISideCar).numPersons() + v.numPersons()) + " seats including side car."); else Console.WriteLine(v.ToString() + " has " + v.numPersons() + " seats and no side car.");
We know that v supports the ISideCar
interface
www.itu.dk
Single Inheritance Interface• An interface can inherit from another interface
public interface ISerialNo { String SerialNo { get; set; }}public interface ILicenseNo : ISerialNo { String LicenseNo { get; set; }}
All vechicles containing a serial number – most but
not baby cycles.
• A BabyCycle does not have any serial or license number.• A Cycle does have a serial number.• If a class has a license number, then there will also be a serial
number.
public class BabyCycle : Vechicle { … }public class Cycle : Vechicle, ISerialNo { … }public class Bike : Vechicle, ILicenseNo { … }public class Car : Vechicle, ILicenseNo { … }
Vechicles with a license number must
also have a serial number
Example file: SingleInheritanceInterface
www.itu.dk
Single Inheritance Interface• Class Diagram having Single Inheritance
www.itu.dk
Single Inheritance Interface• Find all objects that support ISerialNo.
foreach (Vechicle v in vs) if (v is ISerialNo) Console.WriteLine(v.ToString() + " has serial number: " + (v as ISerialNo).SerialNo);
A type that supports ILicenseNo will also support ISerialNo.
• Find all objects that support ILicenseNo. They will also support ISerialNo.
foreach (Vechicle v in vs) if (v is ILicenseNo) Console.WriteLine(v.ToString() + " has serial number: " + (v as ILicenseNo).SerialNo + " and license number: " + (v as ILicenseNo).LicenseNo);
A type that supports ILisenceNo does include the property SerialNo.
www.itu.dk
Multiple Inheritance Interface• An interface can extend other interfaces.
public interface ISerialNo { String SerialNo { get; set; }}public interface ILicenseNo : ISerialNo { String LicenseNo { get; set; }}public interface IVechicleName { String Name { get; set; }}public interface IVechiclesMetaData : ILicenseNo, IVechicleName{ int VechicleId { get; } String ppMetaData();}
We give a vechicle a name, eg brand.
The Meta Data interface extends two other interfaces. There are no name splashes, but that will often be the case. Then use explicit naming.
Example file: MultipleInheritanceInterface
www.itu.dk
Multiple Inheritance Interface• Class Diagram having Multiple Inheritance
www.itu.dk
Multiple Inheritance Interface
• Find all objects that support IVedhicleMetaData and print the meta data.
Console.WriteLine("--- Meta Data ---");foreach (Vechicle v in vs) if (v is IVechiclesMetaData) Console.WriteLine( (v as IVechiclesMetaData).ppMetaData());
public class Bike : Vechicle, IVechiclesMetaData { … public String ppMetaData() { return "Meta data for " + this.name + " of type " + this.vechicleName + NewLine + " Serial number: " + this.serialNo + NewLine + " License number: " + this.licenseNo + NewLine + " Vechicle id: " + this.vechicleId + NewLine; }}
www.itu.dk
Some Built In InterfacesA few interface examples:
– IEnumerable : An interface containing the method GetEnumerator. GetEnumerator returns an object implementing the interface IEnumerator
– IEnumerator : An interface containing methods necessary for the foreach construct, that is, Current, MoveNext and Reset.
– ICloneable : An interface containing a Clone method.There are no rules regarding deep and shallow implementations.
– IComparable : An interface containing a Compare method to compare the actual object.
– IComparer : An interface containing a CompareTo method to compare two objects.
www.itu.dk
Some Built In Interfaces
www.itu.dk
IEnumerable and IEnumerator
• A simple approach is to the a built in enumerator, in this case, in ArrayList.
VechicleContainer vContainer = new VechicleContainer();vContainer.addVechicle(new Cycle());vContainer.addVechicle(new Bike("RX 34213"));vContainer.addVechicle(new Car("GC 45221"));Console.WriteLine("--- Listing Forwards ---");foreach (Vechicle v in vContainer) Console.WriteLine(v.ToString());
public class VechicleContainer : IEnumerable { ArrayList vs; public VechicleContainer() { this.vs = new ArrayList(); } public void addVechicle(Vechicle v) { vs.Add(v); } public IEnumerator GetEnumerator() { return vs.GetEnumerator(); }
Built in enumerator
www.itu.dk
IEnumerable and IEnumerator
• We can also make our own enumerator use yield.
Console.WriteLine("--- Listing Backwards ---");foreach (Vechicle v in vContainer.GetEnumeratorBackwards()) Console.WriteLine(v.ToString());
public class VechicleContainer : IEnumerable { ArrayList vs; public VechicleContainer() { this.vs = new ArrayList(); } public void addVechicle(Vechicle v) { vs.Add(v); }
// A Named Iterator public IEnumerable GetEnumeratorBackwards() { for (int i=vs.Count-1; i>=0; i--) yield return vs[i]; } The keyword yield makes the compiled code
remember the code location each time an element is returned. Computation starts at that
location when returning the next element.
The compiler will implicitly generate a class containing the
GenEnumerator method.
www.itu.dk
IEnumerable and IEnumerator
• You can also code the enumerator your self.
public interface MyOwnGetEnumerator { IEnumerator GetEnumerator(); }
public class VechicleContainer : IEnumerable, IEnumerator, MyOwnGetEnumerator { … public void Reset() {Console.WriteLine("Reset.");this.i=-1;} public bool MoveNext(){Console.WriteLine("MoveNext"); i++; if (i < vs.Count) return true; else return false; } public object Current {get {Console.WriteLine("Current"); return this.vs[i];}}
IEnumerator MyOwnGetEnumerator.GetEnumerator() { return (IEnumerator)this; }}
Console.WriteLine("--- Listing with My Own Enumerator ---");foreach (Vechicle v in (MyOwnGetEnumerator)vContainer) Console.WriteLine(v.ToString());
www.itu.dk
Collections
Classes of System.Collection:•ArrayList : Dynamically sized Array•Hashtable : Collection of objects identified by
a numeric key.•Queue : Standard FIFO queue•SortedList : Sorted list of key value pairs.•Stack : Standard LIFO queue.
•You should know your collections because they do save you time when used properly.•There are many collections to choose from.•You can build your own collections by implementing various interfaces.
However – We want Generics because we then can build
•Collections that are more type safe.•Collections that provide better performance – less boxing and unboxing.•Collections that are polymorphic in the elements they contain•The Framework contains a bunch of prefabricated Generics.
www.itu.dk
GenericsClasses of System.Collections.Generic:
•Dictionary<TKey, TValue> : Generic collection of name / value pairs.
•List<T> : Resizable list of items.•Queue<T> : Standard FIFO queue•SortedDictionary<TKey, TValue> : Sorted
list of name / value pairs.•Stack<T> : Standard LIFO queue.
www.itu.dk
Generics Example: Build a NameListMap that maps string values to a
list of arbitrary typed values T.
// Int listNameListMap<int> intMap = new NameListMap<int>();intMap.insert("A", 1);intMap.insert("A", 2);intMap.insert("B", 3);intMap.insert("B", 4);Console.WriteLine(intMap.pp());
// String listNameListMap<String> stringMap = new NameListMap<string>();stringMap.insert("A", "Hans");stringMap.insert("B", "Grethe");stringMap.insert("A", "Peter");stringMap.insert("B", "Kurt");Console.WriteLine(stringMap.pp());
{ (A [1,2]), (B [3,4])}
{ (A [Hans,Peter]), (B [Grethe,Kurt])}
Example: NameListMap
www.itu.dk
Generics Example: Define the NameListMap class and implement the
map using a Dictionary.
internal class NameListMap<T> { private Dictionary<String, List<T>> map; internal NameListMap() { map = new Dictionary<string, List<T>>(); } …}
The type of elements in the list.
Create the dictionary
internal bool exists(String name) { return map.ContainsKey(name);}
It is easy to check if a name is already in the map.
www.itu.dk
Generics Example: When inserting, we have to check if a key (name)
already exists and add the value element to the list.
If not a new list is created.
internal void insert(String name, T t) { List<T> ls; if (map.TryGetValue(name, out ls)) { ls.Add(t); map.Remove(name); map.Add(name, ls); } else { ls = new List<T>(); ls.Add(t); map.Add(name, ls); }}
Value name exists in the map.
Value name does not exists and a new list is created.
www.itu.dk
Generics Example:
Lookup will return the entire list of values for the given name.
internal List<T> lookup(String name) { List<T> elem = default(List<T>); map.TryGetValue(name, out elem); return elem;}
Use default to initiate an ”empty” element.
www.itu.dk
Delegate and Lambda
•Type safe function pointer•Must be fully applied•Annonymous methods can be declared on the fly•They inherit scope where they are declared.•A lambda is mostly syntactic sugar for anonymous delegates•Lambda:
(<parameters>) => { <implementation>}
•Type check (int i, String s) and Type inference (i, s).•Short notation for one-liners
www.itu.dk
Delegate Example
List<int> l1 = new List<int>(new int[] { 1, 2, 3, 4 });printIntList("Before increment:", l1);
public static void printIntList(String msg, List<int> map) { List<String> xs = new List<string>(); foreach (int x in map) xs.Add(x.ToString()); Console.WriteLine( msg + " [" + String.Join(",", xs.ToArray()) + "]");}
This is really a stupid example, sorry
We define a delegate type and a simple delegate
public delegate RT FuncRT<T0, RT>(T0 a0);
public static FuncRT<int, int> incByOne = delegate(int x) { return x + 1; };
www.itu.dk
Delegate Example
public static List<int> intListMap(List<int> map,FuncRT<int,int> fn) { List<int> map2 = new List<int>(); foreach (int x in map) map2.Add(fn(x)); return map2;}
We make a simple method, that can apply a delegate of type FuncRT<int,int> on a list of integers.
Use the intListMap method on the incOne delegate
List<int> l2 = intListMap(l1, incByOne);printIntList("After increment by 1:", l2);
// Add all elements by one - anonymous delegateList<int> l4 = intListMap(l1,delegate (int x) {return x+1;});printIntList("After increment by 1 (anon):", l4);
www.itu.dk
Delegate Example
// Generate delegate that increments by Xpublic static FuncRT<int, int> genIncByX(int x) { return delegate(int y) { return y + x; };}
A method can also return a delegate. The parameter x is in scope of the delegate.
Generate a delegate that increments with 5.
List<int> l3 = intListMap(l1, genIncByX(5));printIntList("After increment by 5:", l3);
Add elements by one with anonymous delegate.
List<int> l4 = intListMap(l1,delegate (int x) {return x+1;});printIntList("After increment by 1 (anon):", l4);
www.itu.dk
Lambda Example
List<int> l5 = intListMap(l1, (int x) => { return x + 1; });printIntList("After increment by 1 (anon, lambda 1):", l5);
The same examples using lambdas.
The lambda can access variables in scope.
int v = 42; // v is in scope.List<int> l6 = intListMap(l1, x => x + v);printIntList("After increment by 1 (anon, lambda v=42):", l6);
Using a named lambda
public static FuncRT<int, int> incByTwo = x => x + 2;
List<int> l7 = intListMap(l1, incByTwo);printIntList("After increment by 2 (named lambda):", l7);
www.itu.dk
Test Data
You can use the access implementation of the Hotel Reception system.
– Table tblGuest contains 83 guests with real names– Given real guest names you can calculate test data by
some stochastic rules. For instance, you want 80% occupied rooms in January, 40% in February etc.
– If you calculate ahead you should be able to have some interesting test cases, eg., the search agent should also search in periods where all rooms are occupied.
– You can also calculate services received etc.– You should parameterize your program to generate hotels
of different occupation.
www.itu.dk
Stubs
A Web service stub is basically an “empty” implementation of the service that fulfills the web service signature.
You can make stubs static so that they always return the same value or dynamic so that they return what seems to be different values.
If you make it dynamic, then try to have it return values that are good test cases.
www.itu.dk
Assignments1. Make the Vechicle class implement ICloneable using deep
cloning. Use example SingleHeirarkyInterface.
2. Make the Vechicle class implement ICompareable comparing on the field vechicleName. Use example SingleHeirarkyInterface.
3. Implement a Ping service on hotel.itu.dk4. Define a BinaryOp delegate type that operates on two integer
values, eg plus, minus, multiplication and returns an integer.Make a method applyOp that takes two integer arguments and a BinaryOp delegate type and applies the delegate on the two parameters.
Mail your solutions to [email protected].
www.itu.dk
Group Meetings Friday February 131. We all meet at 09.15 (I go by train)2. Group 1: 09.30 – 09.503. Group 2: 09.50 – 10.104. Group 3: 10.10 – 10.305. Group 4: 10.30 – 10.506. Group 5: 10.50 – 11.107. Group 6: 11.10 – 11.30
Top Related