Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 New Features in C# 2.0 Generic Types Iterators Simplified Delegates Anonymous Methods Partial Types Various © University of Linz, Institute for System.

Similar presentations


Presentation on theme: "1 New Features in C# 2.0 Generic Types Iterators Simplified Delegates Anonymous Methods Partial Types Various © University of Linz, Institute for System."— Presentation transcript:

1 1 New Features in C# 2.0 Generic Types Iterators Simplified Delegates Anonymous Methods Partial Types Various © University of Linz, Institute for System Software, 2004 published under the Microsoft Curriculum License released Oct. 2005

2 2 Problems Without Generic Types Assume we need a class that can work with arbitrary objects class Buffer { private object[] data; public void Put(object x) {...} public object Get() {...} } Problems Boxing and type casts needed buffer.Put(3);// boxing imposes run-time costs int x = (int)buffer.Get();// type cast imposes run-time costs One cannot statically enforce homogeneous data structures buffer.Put(3); buffer.Put(new Rectangle()); Rectangle r = (Rectangle)buffer.Get(); // can result in a run-time error! Special types IntBuffer, RectangleBuffer,... introduce redundancy

3 3 Generic Class Buffer class Buffer { private Element[] data; public Buffer(int size) {...} public void Put(Element x) {...} public Element Get() {...} } type parameter (placeholder for some real type)generic type works also for structs and interfaces placeholder type Element can be used like a normal type Usage (instantiation) Buffer a = new Buffer (100); a.Put(3);// accepts only int parameters; no boxing int i = a.Get();// no type cast needed! Buffer b = new Buffer (100); b.Put(new Rectangle());// accepts only Rectangle parameters Rectangle r = b.Get();// no type cast needed! Benefits enforces a homogeneous data structure with compile-time type checking efficient (no boxing, no type casts) Genericity is also available in Ada, Eiffel, C++ (templates), Java 5.0

4 4 Multiple Type Parameters Buffer with priorities class Buffer { private Element[] data; private Priority[] prio; public void Put(Element x, Priority prio) {...} public void Get(out Element x, out Priority prio) {...} } Usage Buffer a = new Buffer (); a.Put(100, 0); int elem, prio; a.Get(out elem, out prio); Buffer b = new Buffer (); b.Put(new Rectangle(), 0.5); Rectangle r; double prio; b.Get(out r, out prio);

5 5 Constraints Constraints about placeholder types are specified as base types class OrderedBuffer where Priority: IComparable { Element[] data; Priority[] prio; int lastElem;... public void Put(Element x, Priority p) { int i = lastElement; while (i >= 0 && p.CompareTo(prio[i]) > 0) {data[i+1] = data[i]; prio[i+1] = prio[i]; i--;} data[i+1] = x; prio[i+1] = p; } Allows operations on instances of placeholder types interface or base class Usage OrderedBuffer a = new OrderedBuffer (); a.Put(100, 3); parameter must implement IComparable

6 6 Multiple Constraints class OrderedBuffer where Element: MyClass where Priority: IComparable where Priority: ISerializable {... public void Put(Element x, Priority p) {...} public void Get(out Element x, out Priority p) {...} } Usage OrderedBuffer a = new OrderedBuffer ();... a.Put(new MySubclass(), new MyPrio(100)); must implement IComparable and ISerializable must be a subclass of MyClass

7 7 Constructor Constraint For creating objects of a parameter type class Stack where E: Exception, new() { T[] data =...; int top = -1; public void Push(T x) { if (top >= data.Length - 1) throw new E(); else data[++top] = x; } specifies that the placeholder E must have a parameterless constructor. class MyException: Exception { public MyException(): base("stack overflow or underflow") {} } Usage Stack stack = new Stack ();... stack.Push(3);

8 8 Genericity and Inheritance class Buffer : List {... public void Put(Element x) { this.Add(x); // Add is inherited from List } From which classes may a generic class be derived? from a non-generic class class T : B {...} from an instantiated generic class class T : B {...} from a generic class class T : B {...} with the same placeholder can also implement generic interfaces

9 9 Assignment Compatibility class A {...} class B :A {...} class C :A {...} A B C... A a1 = new B (); A a2 = new C (); B... C... Compatibiliy between T and a non-generic base class class A {...} class B :A {...} class C :A {...} A a1 = new B (); A a2 = new C (); Compatibility between T and a generic base class A B C... A a3 = new B (); illegal (but there is a solution for it in C# 4.0) ok, if corresponding placeholders are replaced by the same type

10 10 Overriding Methods class MyBuffer: Buffer {... public override void Put(int x) {...} } Methods inherited from an instantiated generic class Element is replaced by the concrete type int class Buffer {... public virtual void Put(Element x) {...} } class MyBuffer : Buffer {... public override void Put(Element x) {...} } Methods inherited from a generic class Element remains to be a placeholder The following is illegal (a concrete class cannot inherit from a generic class) class MyBuffer: Buffer {... public override void Put(Element x) {...} }

11 11 Run-time Type Checks Instantiated generic types can be used like non-generic types Buffer buf = new Buffer (20); object obj = buf; if (obj is Buffer ) buf = (Buffer ) obj; Type t = typeof(Buffer ); Console.WriteLine(t.FullName); // => Buffer'1[[System.Int32,...]] Reflection yields also the concrete types substituted for the placeholders! All this is not possible in Java, because in Java generic types exist only at compile time but not at run time

12 12 Generic Methods Methods that can work with arbitrary data types static void Sort (T[] a) where T: IComparable { for (int i = 0; i < a.Length-1; i++) { for (int j = i+1; j < a.Length; j++) { if (a[j].CompareTo(a[i]) < 0) { T x = a[i]; a[i] = a[j]; a[j] = x; } can sort any array as long as the array elements implement IComparable Usage int[] a = {3, 7, 2, 5, 3};... Sort (a); // a == {2, 3, 3, 5, 7} string[] s = {"one", "two", "three"};... Sort (s); // s == {"one", "three", "two"} From the method parameters the compiler can usually infer the concrete type that is to be substituted for the placeholder type; so one can simply write: Sort(a); // a == {2, 3, 3, 5, 7}Sort(s); // s == {"one", "three", "two"}

13 13 Generic Delegates delegate bool Match (T value); class Payment { public DateTime date; public int amount; } class Account { List payments = new List ();... public int AmountPayed(Match match) { int val = 0; foreach (Payment p in payments) if (match(p)) val += p.amount; return val; } bool After_9_11(Payment p) { return DateTime.Compare(p.date, new DateTime(2001, 11, 9)) >= 0; }... int val = account.AmountPayed(After_9_11); A method is passed, which checks for every payment, whether it matches a certain criterion

14 14 Null Values Setting a value to null void Foo () { T x = null;// error T y = 0;// error T z = default(T);// ok! 0, '\0', false, null } Comparing a value against null void Foo (T x) { if (x == null) { Console.WriteLine(true); } else { Console.WriteLine(false); } Foo(3);// false Foo(0);// false Foo("Hello");// false Foo (null);// true for reference types x == null does a comparison for value types x == null returns false

15 15 Namespace System.Collections.Generic New generic types Classes List Dictionary SortedList Stack Queue Interfaces ICollection IList IDictionary IEnumerable IEnumerator IComparable IComparer corresponds to ArrayList corresponds to Hashtable

16 16 What Happens Behind the Scene? class Buffer {...} Compiler generates CIL code for class Buffer with a placeholder for Element. Buffer a = new Buffer (); The JIT compiler generates a new class Buffer in which Element is replaced with int. Buffer b = new Buffer (); Reuses existing Buffer. Buffer c = new Buffer (); The JIT compiler generates a new class Buffer in which Element is replaced with float. Instantiation with value types Buffer a = new Buffer (); The JIT compiler generates a new class Buffer which can work with all reference types. Buffer b = new Buffer (); Reuses existing Buffer. Instantiation with reference types Buffer b = new Buffer (); Reuses existing Buffer.

17 17 Differences to Other Languages C++ template class Buffer {... Element Get(); } Buffer b1; no constraints, less type-safe placeholders can also be used for constants Java since Version 5.0 placeholders can only be instantiated with reference types placeholders are mapped to type Object generates implicit type casts (imposes tun-time costs) generics are just in the Java language and not in the VM reflection does not yield exact type information about placeholders class Buffer {... Element Get() {...} } Buffer b1;

18 18 New Features in C# 2.0 Generic Types Iterators Simplified Delegates Anonymous Methods Partial Types Various © University of Linz, Institute for System Software, 2004 published under the Microsoft Curriculum License

19 19 Iterators so far foreach loop can be applied to objects of classes which implement IEnumerable class MyClass: IEnumerable {... public IEnumerator GetEnumerator() { return new MyEnumerator(...); } class MyEnumerator: IEnumerator { public object Current { get {...} } public bool MoveNext() {...} public void Reset() {...} } MyClass x = new MyClass();... foreach (object obj in x)... complicated to implement!! interface IEnumerable { IEnumerator GetEnumerator(); } interface IEnumerator { object Current; bool MoveNext(); void Reset(); }

20 20 Iterator Methods class MyClass { string first = "first"; string second = "second"; string third = "third";... public IEnumerator GetEnumerator() { yield return first; yield return second; yield return third; } Characteristics of an iterator method 1.has the signature public IEnumerator GetEnumerator 2.statement body contains at least one yield statement MyClass x = new MyClass();... foreach (string s in x) Console.Write(s + " "); // prints "first second third" 1.returns a sequence of values 2.foreach loop traverses this sequence How does an iterator method work? Note MyClass needs not implement IEnumerable! Instead of IEnumerator it is better to use IEnumerator here (avoids a type cast) IEnumerator is in System.Collections.Generic

21 21 What Happens Behind the Scene? public IEnumerator GetEnumerator() { try {... } finally {... } returns an object of the following compiler-generated class class _Enumerator : IEnumerator { int Current { get {...} } bool MoveNext() {...} void Dispose() {...} } foreach (int x in list) Console.WriteLine(x); is translated into IEnumerator _e = list.GetEnumerator(); try { while (_e.MoveNext()) Console.WriteLine(_e.Current); } finally { if (_e != null) _e.Dispose(); } MoveNext runs to the next yield statement Dispose executes a possibly existing finally block in the iterator method

22 22 yield Statement 2 kinds yield return expr; yields a value for the next iteration of the foreach loop type of expr must be compatible with - T (if IEnumerator ) - object (if IEnumerator) yield break; terminates the iteration (may only occur in iterator methods)

23 23 Specific Iterators class MyList { int[] data =...; public IEnumerator GetEnumerator() { for (int i = 0; i < data.Length; i++) yield return data[i]; } Standard iterator method Specific iterator method arbitrary name and parameter list result type IEnumerable or IEnumerable must contain a yield statement public IEnumerable Range(int from, int to) { if (to > data.Length) to = data.Length; for (int i = from; i < to; i++) yield return data[i]; } Specific iterator property arbitrary name result type IEnumerable or IEnumerable must contain a yield statement public IEnumerable Downwards { get { for (int i = data.Length - 1; i >= 0; i--) yield return data[i]; } MyList list = new MyList(); foreach (int x in list) Console.WriteLine(x); foreach (int x in list.Range(2, 7)) Console.WriteLine(x); foreach (int x in list.Downwards) Console.WriteLine(x);

24 24 How Specific Iterators are Compiled public IEnumerable Range(int from, int to) { if (to > data.Length) to = data.Length; for (int i = from; i < to; i++) yield return data[i]; } class _Enumerable : IEnumerable { IEnumerator GetEnumerator() {...} } class _Enumerator : IEnumerator { int from, to; int Current { get {...} } bool MoveNext() {...} void Dispose() {..} } returns an object of the following class this returns an object of the following class foreach (int x in list.Range(2, 7)) Console.WriteLine(x); IEnumerator _e = list.Range(2, 7).GetEnumerator(); try { while (_e.MoveNext()) Console.WriteLine(_e.Current); } finally { if (_e != null) _e.Dispose(); } is translated into

25 25 Example: Iterating Over a Tree class Tree { Node root = null; public void Add(int val) {...} public bool Contains(int val) {...} public IEnumerator GetEnumerator() { return root.GetEnumerator(); } class Node { public int val; public Node left, right; public Node(int x) { val = x; } }... Tree tree = new Tree();... foreach (int x in tree) Console.WriteLine(x); Usage Creates an enumerator object for every node of the tree! public IEnumerator GetEnumerator() { if (left != null) foreach (int x in left) yield return x; yield return val; if (right != null) foreach (int x in right) yield return x; }

26 26 New Features in C# 2.0 Generic Types Iterators Simplified Delegates Anonymous Methods Partial Types Various © University of Linz, Institute for System Software, 2004 published under the Microsoft Curriculum License

27 27 Simplified Creation of Delegates delegate void Printer(string s); void Foo(string s) { Console.WriteLine(s); } Printer print; print = new Printer(this.Foo); print = this.Foo; print = Foo; simplified form: delegate type is infered from the type of the left-hand side delegate double Function(double x); double Foo(double x) { return x * x; } Printer print = Foo; Function square = Foo; assigns Foo(string s) assigns Foo(double x) overloading is resolved using the type of the left-hand side

28 28 New Features in C# 2.0 Generic Types Iterators Simplified Delegates Anonymous Methods Partial Types Various © University of Linz, Institute for System Software, 2004 published under the Microsoft Curriculum License

29 29 Ordinary Delegates class C { int sum = 0; void SumUp(Node p) { sum += p.value; } void Print(Node p) { Console.WriteLine(p.value); } void Main() { List list = new List(); list.ForAll(SumUp); list.ForAll(Print); } requires the declaration of named methods (SumUp, Print,...) SumUp and Print cannot access the local variables of Main => sum must be declared as a global field delegate void Visitor(Node p); class List { Node[] data =...;... public void ForAll(Visitor visit) { for (int i = 0; i < data.Length; i++) visit(data[i]); }

30 30 Anonymous Methods delegate void Visitor(Node p); class C { void Main() { List list = new List(); int sum = 0; list.ForAll(delegate (Node p) { Console.WriteLine(p.value); }); list.ForAll(delegate (Node p) { sum += p.value; }); } method body is specified in-place does not require the declaration of a named method anonymous method can access Main's local variable sum both anonymous methods are of type Visitor here return terminates the anonymous method (not the enclosing method) formal parameterbody class List {... public void ForAll(Visitor visit) {... } Restrictions anonymous methods must not have formal parameters of the kind params T[] anonymous methods must not access ref or out parameters of the enclosing method

31 31 Further Simplification Button button = new Button(); button.Click += delegate (object sender, EventArgs arg) { Console.WriteLine("clicked"); }; Can be simplified as follows button.Click += delegate { Console.WriteLine("clicked"); }; Formal parameters can be omitted if they are not used in the method body Restriction Formal parameters can only be omitted if the delegate type does not have out parameters delegate void EventHandler (object sender, EventArgs arg);

32 32 Outer Variables If anonymous methods access variables of the enclosing method these variables are evacuated to the heap (capturing). delegate int Adder(); class Test { static Adder CreateAdder() { int x = 0; return delegate { x++; return x; }; } static void Main() { Adder add = CreateAdder(); Console.WriteLine(add()); } 123123 Output: x++; return x; 0 x on the heap method add 123 The x on the heap lives as long as the method object

33 33 New Features in C# 2.0 Generic Types Iterators Simplified Delegates Anonymous Methods Partial Types Various © University of Linz, Institute for System Software, 2004 published under the Microsoft Curriculum License

34 34 Class Consisting of Multiple Parts public partial class C { int x; public void M1(...) {...} public int M2(...) {...} } file Part1.cs public partial class C { string y; public void M3(...) {...} public void M4(...) {...} public void M5(...) {...} } file Part2.cs What are partial classes used for? One part can be machine-generated, other parts can be hand-written Should only be used in rare cases

35 35 New Features in C# 2.0 Generic Types Iterators Simplified Delegates Anonymous Methods Partial Types Various © University of Linz, Institute for System Software, 2004 published under the Microsoft Curriculum License

36 36 Static Classes May only have static fields and methods static class Math { public static double Sin(double x) {...} public static double Cos(double x) {...}... } Benefit shows explicitly that this class contains only static members the compiler can make sure that all members are declared as static Static classes must not be used as types


Download ppt "1 New Features in C# 2.0 Generic Types Iterators Simplified Delegates Anonymous Methods Partial Types Various © University of Linz, Institute for System."

Similar presentations


Ads by Google