Advantages of Generics
It's not difficult to see the advantages of using generics:
□ Type safety — Generic types enforce type compliance at compile time, not at runtime (as in the case of using Object
). This reduces the chances of data-type conflict during runtime.
□ Performance — The data types to be used in a generic class are determined at compile time, so there's no need to perform type casting during runtime, which is a computationally costly process.
□ Code reuse — Because you need to write the class only once and then customize it for use with the various data types, there is a substantial amount of code reuse.
Using Constraints in a Generic Type
Using the MyStack
class, suppose that you want to add a method called Find()
that allows users to check if the stack contains a specific item. You implement the Find()
method like this:
public class MyStack<T> {
private T[] _elements;
private int _pointer;
public MyStack(int size) {
_elements = new T[size];
_pointer = 0;
}
public void Push(T item) {
if (_pointer > _elements.Length - 1) {
throw new Exception('Stack is full.');
}
_elements[_pointer] = item;
_pointer++;
}
public T Pop() {
_pointer--;
if (_pointer < 0) {
return default(T);
//throw new Exception('Stack is empty.');
}
return _elements[_pointer];
}
}
But the code will not compile. This is because of the statement:
That's because the compiler has no way of knowing if the actual type of item
and keyword
(type T
) support this operator (see Figure 9-3). For example, you cannot by default compare
two struct objects.

Figure 9-3
A better way to resolve this problem is to apply constraint to the generic class so that only certain data types can be used. In this case, because you want to perform comparison in the Find()
method, the data type used by the generic class must implement the IComparable<T>
interface. This is enforced by using the where
keyword:
private T[] _elements;
private int _pointer;
public MyStack(int size) {
_elements = new T[size];
_pointer = 0;
}
public void Push(T item) {
if (_pointer > _elements.Length - 1) {
throw new Exception('Stack is full.');
}
_elements[_pointer] = item;
_pointer++;
}
public T Pop() {
_pointer--;
if (_pointer < 0) {
return default(T);
}
return _elements[_pointer];
}
public bool Find(T keyword) {
bool found = false;
for (int i=0; i<_pointer; i++) {
found = true;
break;
}
}
return found;
}
}
For the comparison, you use the CompareTo()
method to compare two items of type T
(which must implement the IComparable
interface). The CompareTo()
method returns 0 if the two objects are equal. You can now search for an item by using the Find