You are on page 1of 6

CS193N HO# 7 7/2/07

Generics, Constructors, Properties,


Iterators

Stack s = new Stack();


s.Push(19);
Boxing
Topics for today: s.Push(28);
int x = (int) s.Pop();
Unboxing
int y = (int) s.Pop();
• Generics
Cast required
• Constructors and Inheritance
class Stack
{
• Properties
private object[] _itemsArray;
...
• Iterators
public void Push(object item)
{ ... }
public object Pop()
{ ... }
}

Stack s = new Stack(); IntStack s = new IntStack();


s.Push("hi there"); s.Push(19);
s.Push(28); This compiles but s.Push(28); No boxing or casting, and
int x = (int) s.Pop(); throws an exception int x = s.Pop(); s.Push("hi there") would
int y = (int) s.Pop(); at runtime. int y = s.Pop(); not compile. But we need a
separate class for every type.

class Stack class IntStack


{ {
private object[] _itemsArray; private int[] _itemsArray;
... ...
public void Push(object item) public void Push(int item)
{ ... } { ... }
public object Pop() public int Pop()
{ ... } { ... }
} }

Stack<int> s = new Stack<int>();


s.Push(19);
s.Push(28); s.Push("hi there");
int x = s.Pop(); and
int y = s.Pop(); string str = s.Pop();
will not compile.

class Stack<T> class Stack<T>


{ {
private T[] _itemsArray; private T[] _itemsArray;
... ...
public void Push(T item) public void Push(T item)
{ ... } { ... }
public T Pop() public T Pop()
{ ... } { ... }
} }

1
CS193N HO# 7 7/2/07
Generics, Constructors, Properties,
Iterators

C# allows: Classes included in the Framework Class Library

Generic reference types (classes) Generic Collection Class Non-Generic


Generic value types (structs)
Generic interfaces List<T> ArrayList
Generic delegates SortedList<TKey, TValue> SortedList
Generic methods Dictionary<TKey, TValue> Hashtable
SortedDictionary<TKey, TValue> SortedList
Stack<T> Stack
Advantages: Queue<T> Queue
LinkedList<T> (none)
Type safety
Cleaner code
Better performance

Classes included in Wintellect's Power Collection Library class Stack<T>


{
http://Wintellect.com (download and use free of charge) private T[] _itemsArray;

public bool Contains(T t)


{
BigList<T> for( int i = 0; i < _index; i++)
Bag<T> {
OrderedBag<T> if (_itemsArray[i] == t) return true;
}
Set<T>
return false;
OrderedSet<T> }
Deque<T> } This will not compile, because the
OrderedDictionary<TKey, TValue> compiler does not know whether the
MultiDictionary<TKey, TValue> type supplied will support ==
OrderedMultiDictionary<TKey, TValue>

class Stack<T> class Stack<T>


{ {
private T[] _itemsArray; private T[] _itemsArray;

public bool Contains(T t) public bool Contains(T t)


{ {
for( int i = 0; i < _index; i++) for( int i = 0; i < _index; i++)
{ {
if (_itemsArray[i].CompareTo(t) == 0) return true; if (_itemsArray[i].CompareTo(t) == 0) return true;
} }
return false; return false;
} }
} This will not compile, because the } Casting this to IComparable could
compiler does not know whether the cause a run-time exception if T
public interace IComparable type supplied is derived from public interace IComparable does not support IComparable and
{ IComparable. { would lead to boxing if T is a value
int CompareTo(object obj); int CompareTo(object obj); type.
} }

2
CS193N HO# 7 7/2/07
Generics, Constructors, Properties,
Iterators

class Stack<T> where T : IComparable class Stack<T> where T : IComparable<T>


{ {
private T[] _itemsArray; private T[] _itemsArray;

public bool Contains(T t) public bool Contains(T t)


{ {
for( int i = 0; i < _index; i++) for( int i = 0; i < _index; i++)
{ {
if (_itemsArray[i].CompareTo(t) == 0) return true; if (_itemsArray[i].CompareTo(t) == 0) return true;
} }
return false; return false;
} }
} We will still box }
value types.

public interace IComparable public interace IComparable<T>


{ {
int CompareTo(object obj); int CompareTo(T t);
} }

There are three kinds of constraints References


Derivation constraints

public class MyList<K,T> : IEnumerable<T> An Introduction to C# Generics


where K : MyBaseClass, IComparable<K> Juval Löwy
IDesign
Constructor constraint
http://msdn2.microsoft.com/en-us/library/ms379564(vs.80).aspx
public MyClass<T> where T: new()

Reference/value constraint
Introducing Generics in the CLR
public MyClass<T> where T: class Jason Clark
public MyClass<T> where T: struct Wintellect

http://msdn.microsoft.com/msdnmag/issues/06/00/NET/default.aspx

Method Hiding
class Super
{
public Super() {. . .};

public void DoSomething() (not virtual)


{
. . .

Visual Studio Example


}
}

Constructors and Inheritance


class Sub : Super
{
This "hides" the method of the
public Sub() {. . .};
parent, making it inaccessible
public new void DoSomething() through the derived class. This
{ applies to any class member.
. . . A compiler warning is given
} unless the new keyword is used.
}

3
CS193N HO# 7 7/2/07
Generics, Constructors, Properties,
Iterators

Properties class Square Properties


{
class Square class SquareUser private double side;
{ { private const double MAX_SIDE = 10.0;
private double side; private Square sqr = public Square(double side)
new Square(4); { class SquareUser
public Square(double side) private double size; this.side = side; {
} private Square sqr =
{ . . .
public void Grow() new Square(4);
this.side = side; // possibly calls {
} // sqr.Grow() private double size;
side *= 2;
public void Grow() . . . }
. . .
{ size = sqr.Side; public double Side // possibly calls
side *= 2; { // sqr.Grow()
} } get {return side;} . . .
set size = sqr.Side;
public double Side { sqr.Side = 12;
if (value <= MAX_SIDE) }
{
side = value;
get {return side;} else
} Property side = MAX_SIDE;
} }
}
}

class Square
{
private double side;
Things to do if the value in the "set" method is inappropriate: private const double MAX_SIDE = 10.0;
public Square(double side)
• Do nothing {
this.side = side;
}
• Assign a default value public void Grow()
{
• Do nothing but log the event side *= 2;
}
• Throw an exception public double Area
{
get {return side * side;}
}
}
The get method can also do some processing.

Arrays Arrays
Single dimension
Point[][] myPolygons = new Point[3][];
int[] myInts = new int[20];
myPolygons[0] = new Point[10];
. . .
Console.WriteLine(myInts[i]); myPolygons[1] = new Point[20];
myPolygons[2] = new Point[30];
Multidimension
string[,] myStrings = new string[5,6]; for (int x = 0; x < myPolygons[1].Length; x++)
double[,,] myDoubles = new double[3,8,5]; Console.WriteLine(myPolygons[1][x]);
. . .
Console.WriteLine(myDoubles[i,j,k]); foreach (Point p in myPolygons[1])
Jagged Console.WriteLine(p);
Point[][] myPolygons = new Point[3][];
myPolygons[0] = new Point[10]; foreach (Point[] ptArray in myPolygons)
myPolygons[1] = new Point[20]; foreach (Point p in ptArray)
myPolygons[2] = new Point[30]; Console.WriteLine(p);
. . .
for (int x = 0; x < myPolygons[1].Length; x++)
Console.WriteLine(myPolygons[1][x]); Note: inside a foreach loop we have
read only access to the array elements.

4
CS193N HO# 7 7/2/07
Generics, Constructors, Properties,
Iterators

Arrays
myInts ///// (overhead)
4
int[] myInts; Creates a variable that can point to an array 0
7 Managed
Heap
Creates an array of 100 ints.
.
myInts = new int[100]; .
These ints are initialized to 0, and .
stored, unboxed, in a memory block 0
on the managed heap. 0

myControls ///// (overhead)


null
Control[] myControls; Creates a variable that can point to an array Button
null
myControls = new Control[100]; .
.
Creates an array of Control references, initialized
.
TextBox
to null. Since Control is a reference type, creating
the array creates references—the actual objects null
are not created.

Array Initialization Arrays are implicitly derived from System.Array


Single dimension
int[] myInts = new int[3] {1, 2, 3}; int[] myInts = new int[3] {1, 2, 3};

int[] myInts = new int[] {1, 2, 3}; double[,,] myDoubles = new double[3,8,5];

int[] myInts = {1, 2, 3}; Properties myInts.Length is 3


myInts.Rank is 1

myDoubles.Length is 120
myDoubles.Rank is 3
myDoubles.GetLength(1) is 8

Static
Methods Array.Sort(myInts);
Array.Sort(keys, items);
Array.Reverse(myInts);
Array.Clear(myInts);
int i = Array.IndexOf(myInts, 2);

Iteration: How does foreach work, and class MyCollectionClass : IEnumerable


How do we make it work with our classes? { ... }

foreach (string s in myCollection)


{
Console.WriteLine("String is {0}", s);
}

is transformed into

IEnumerator enumerator =
((IEnumerable) myCollection).GetEnumerator();

while (enumerator.MoveNext())
{
string s = (string) enumerator.Current;
Console.WriteLine("String is {0}", s);
}

5
CS193N HO# 7 7/2/07
Generics, Constructors, Properties,
Iterators

public interface IEnumerable class MyCollectionClass : IEnumerable


{ {
IEnumerator GetEnumerator(); CollectionPart[] _parts;
} ...
...
public interface IEnumerator public IEnumerator GetEnumerator()
{ {
object Current { get; }
bool MoveNext(); }
void Reset(); }
}

class MyCollectionClass : IEnumerable •Suppose MyCollectionClass stores the parts in a custom linked
{ list.
CollectionPart[] _parts;
... •It has a member _head that refers to the first node in the list.
...
public IEnumerator GetEnumerator() •The nodes have Data and Next properties.
{
return _parts.GetEnumerator();
} class MyCollectionClass : IEnumerable
} {
Since _parts is a System.Array, MySpecialLinkedList _parts;
which is enumerable, it has a Node _head;
GetEnumerator method. ...
public IEnumerator GetEnumerator()
We can just return the IEnumerator {
that we get from calling that method.
}
}

In C# 2.0 we can implement the iterator with a yield block

class MyCollectionClass : IEnumerable


{
MySpecialLinkedList _parts;
Node _head;
...
public IEnumerator GetEnumerator() Visual Studio example using a generic class
{
Node current = _head;

while (current != null)


{
yield return current.Data;
current = current.Next;
}
}
}

You might also like