Generics
Chapter 20 of Visual C# How to Program, 6/e
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.2 Motivation for Generic Methods
Overloaded methods are often used to perform similar operations on different
types of data.
To understand the motivation for generic methods, let’s begin with an example
(Fig. 20.1) that contains three overloaded DisplayArray methods.
These methods display the elements of an int array, a double array and a char
array, respectively.
Soon, we’ll reimplement this program more concisely and elegantly using a
single generic method
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.3 Generic-Method Implementation
Figure 20.3 reimplements the app of Fig. 20.1 using a generic
DisplayArray method
Note that the DisplayArray method calls in lines 15, 17 and 19 are
identical to those of Fig. 20.1, the outputs of the two apps are identical
and the code in Fig. 20.3 is 22 lines shorter than that in Fig. 20.1.
As illustrated in Fig. 20.3, generics enable us to create and test our code
once, then reuse it for many different types of data.
This effectively demonstrates the expressive power of generics.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.3 Generic-Method Implementation
Value Types vs. Reference Types in Generics
The compiler handles value and reference types differently in generic method
calls.
When a value-type argument is used for a given type parameter, the compiler
generates a version of the method that’s specific to the value type—if one has
been generated previously, the compiler reuses that one.
If DisplayArray were called with a reference type, the compiler would also
generate a single version of the method that’s used by all reference types.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.3 Generic-Method Implementation
Explicit Type Arguments
You also can use explicit type arguments to indicate the exact type that should
be used to call a generic function. For example, line 15 could be written as
DisplayArray<int>(intArray); // pass an int array argument
The preceding method call explicitly provides the type argument (int) that
should be used to replace type parameter T in line 23.
Though not required here, an explicit type argument would be required if the
compiler cannot infer the type from the method’s argument(s).
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.4 Type Constraints
IComparable<T> Interface
It’s possible to compare two objects of the same type if that type implements the
generic interface IComparable<T> (of namespace System).
A benefit of implementing interface IComparable<T> is that
IComparable<T> objects can be used with the sorting and searching methods
of classes in the System.Collections.Generic namespace—we discuss
those methods in Chapter 21.
The structures in the Framework Class Library that correspond to the simple
types all implement this interface.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.4 Type Constraints (cont.)
Specifying Type Constraints
Even though IComparable objects can be compared, they cannot be used with
generic code by default, because not all types implement interface
IComparable<T>.
However, we can restrict the types that can be used with a generic method or
class to ensure that they meet certain requirements.
This feature—known as a type constraint—restricts the type of the argument
supplied to a particular type parameter.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.4 Type Constraints (cont.)
Figure 20.4 declares method Maximum (lines 18–35) with a type
constraint that requires each of the method’s arguments to be of
type IComparable<T>.
This restriction is important, because not all objects can be
compared.
However, all IComparable<T> objects are guaranteed to have a
CompareTo method that can be used in method Maximum to
determine the largest of its three arguments.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.4 Type Constraints (cont.)
C# provides several kinds of type constraints.
A class constraint indicates that the type argument must be an object of
a specific base class or one of its subclasses.
An interface constraint indicates that the type argument’s class must
implement a specific interface.
The type constraint in line 18 is an interface constraint, because
IComparable<T> is an interface.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.4 Type Constraints (cont.)
You can specify that the type argument must be a reference type or a
value type by using the reference-type constraint (class) or the
value-type constraint (struct), respectively.
Finally, you can specify a constructor constraint—new()—to
indicate that the generic code can use operator new to create new
objects of the type represented by the type parameter.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.4 Type Constraints (cont.)
If a type parameter is specified with a constructor constraint, the type
argument’s class must provide a public parameterless or default
constructor to ensure that objects of the class can be created without
passing constructor arguments; otherwise, a compilation error occurs.
It’s possible to apply multiple constraints to a type parameter.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.4 Type Constraints (cont.)
To do so, simply provide a comma-separated list of constraints in the
where clause.
If you have a class constraint, reference-type constraint or value-type
constraint, it must be listed first—only one of these types of
constraints can be used for each type parameter.
Interface constraints (if any) are listed next.
The constructor constraint is listed last (if there is one).
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.5 Overloading Generic Methods
A generic method may be overloaded.
Each overloaded method must have a unique signature (as discussed in
Chapter 7).
A class can provide two or more generic methods with the same name
but different method parameters.
A generic method can be overloaded by nongeneric methods with the
same method name.
When the compiler encounters a method call, it searches for the
method declaration that best matches the method name and the
argument types specified in the call.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.6 Generic Classes
With a generic class, you can use a simple, concise notation to indicate
the actual type(s) that should be used in place of the class’s type
parameter(s).
At compilation time, the compiler ensures your code’s type safety, and
the runtime system replaces type parameters with type arguments to
enable your client code to interact with the generic class.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.6 Generic Classes (cont.)
One generic Stack class, for example, could be the basis for creating
many Stack classes (e.g., “Stack of double,” “Stack of int,”
“Stack of char,” “Stack of Employee”).
Figure 20.5 presents a generic Stack class declaration.
This class should not be confused with the class Stack from
namespace System.Collections.Generics.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.6 Generic Classes (cont.)
Classes FullStackException (Fig. 20.6) and
EmptyStackException (Fig. 20.7) each provide a parameterless
constructor, a one-argument constructor of exception classes (as
discussed in Section 13.8) and a two-argument constructor for creating
a new exception using an existing one.
The parameterless constructor sets the default error message while the
other two constructors set custom error messages.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.6 Generic Classes (cont.)
Now, let’s consider an app (Fig. 20.8) that uses the Stack generic
class.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
20.6 Generic Classes (cont.)
Figure 20.9 declares generic method TestPush (lines 33–53) to
perform the same tasks as TestPushDouble and TestPushInt in
Fig. 20.8—that is, Push values onto a Stack<T>.
Similarly, generic method TestPop (lines 56–77) performs the same
tasks as TestPopDouble and TestPopInt in Fig. 20.8—that is, Pop
values off a Stack<T>.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.
©1992-2017 by Pearson Education, Inc. All Rights Reserved.