Generics
To understand and appreciate the concept of generics, consider
the need to create a class that will manage a collection of objects. The objects
may be of any type and are specified at compile time by a parameter passed to
the class. Moreover, the collection class must be type-safe—meaning that it will
accept only objects of the specified type.
In the 1.x versions of .NET, there is no way to create such a
class. Your best option is to create a class that contains an array (or other
container type) that treats everything as an object. As shown here, casting, or
an as operator, is then required to access the actual object type. It
is also necessary to include code that verifies the stored object is the correct
type.
Object[] myStack = new object[50]; myStack[0] = new Circle(5.0); // place Circle object in array myStack[1] = "Circle"; // place string in array Circle c1 = myStack[0] as Circle; if( c1!=null) { // circle object obtained Circle c2 = (Circle) myStack[1]; // invalid case exception
Generics, introduced with .NET 2.0, offer an elegant solution
that eliminates the casting, explicit type checking, and boxing that occurs for
value type objects. The primary challenge of working with generics is getting
used to the syntax, which can be used with a class, interface, or structure.
The best way to approach the syntax is to think of it as a way
to pass the data type you'll be working with as a parameter to the generic
class. Here is the declaration for a generic class:
public class myCollection<T> { T[] myStack = new T[50]; }
The type parameter T is
placed in brackets and serves as a placeholder for the actual type. The compiler
recognizes any reference to T within the body of the class and replaces
it with the actual type requested. As this statement shows, creating an instance
of a generic class is straightforward:
myCollection <string> = new myCollection<string>;
In this case, string is a type
argument and specifies that the class is to work with string
types only. Note that more than one type parameter may be used, and that the type parameter can be any name, although Microsoft
uses (and recommends) single characters in its generic classes.
Although a class may be generic, it can restrict the types that
it will accept. This is done by including an optional list of
constraints for each type parameter. To declare a constraint, add the
where keyword followed by a list of parameter/requirement pairs. The
following declaration requires that the type parameter implement the
ISerializable and IComparable interfaces:
public class myCollection<T> where T:ISerializable, T:IComparable
A parameter may have multiple interface constraints and a
single class restraint. In addition, there are three special constraints to be
aware of:
class— Parameter must be reference type.
struct— Parameter must be value type.
new()— Type parameter must have a parameterless
constructor.
An example of a generic class is provided in Listing 3-16. The class implements an array that manages
objects of the type specified in the type parameter. It includes methods to add
items to the array, compare items, and return an item count. It includes one
constraint that restricts the type parameter to a reference type.
Listing 3-16. A Generic Class to Hold Data
using System.Collections.Generic public class GenStack<T> where T:class // constraint restricts access to ref types { private T[] stackCollection; private int count = 0; // Constructor public GenStack(int size) { stackCollection = new T[size]; } public void Add(T item) { stackCollection[count] = item; count += 1; } // Indexer to expose elements in internal array public T this[int ndx] { get { if (!(ndx < 0 || ndx > count - 1)) return stackCollection[ndx]; // Return empty object else return (default(T)); } } public int ItemCount { get {return count;} } public int Compare<C>(T value1, T value2) { // Case-sensitive comparison: -1, 0(match), 1 return Comparer<T>.Default.Compare(value1, value2); } }
The following code demonstrates how a client could access the
generic class described in Listing
3-16:
// Create instance to hold 10 items of type string GenStack<string> myStack = new GenStack<string>(10); myStack.Add("Leslie"); myStack.Add("Joanna"); Console.WriteLine(myStack.ItemCount); // 2 Console.WriteLine(myStack[1]); // Joanna int rel = myStack.Compare<string>("Joanna", "joanna"); // -1 Console.WriteLine(rel.ToString());
No comments:
Post a Comment
Comment Here