Unlocking the Power of Generics
Matt Goebel Crowe Chizek CNUG February 15, 2006
Agenda
Traditional Collections and Drawbacks Introduction to Generics Value of Generics Syntax and Samples
Traditional Collections
[Link] namespace introduced in 1.0 version of .NET Framework Useful container types
Lists Dictionaries Hashtables CollectionBase
Sample Class Definition
class Book { private int bookNumber = 0; public int BookNumber { get { return [Link] ; } set { this. bookNumber = value; } } public Book( int _bookNumber ) { [Link] = _bookNumber; } }
Sample ArrayList Use
ArrayList bookList = new ArrayList(); for( int i = 0; i < 20; i++) { [Link]( new Book(i) ); } IEnumerator listEnum = [Link](); while( [Link]() ) { [Link]({0}, ((Book)([Link])).BookNumber); }
Drawbacks
No type checking enforcement at compile time
Doesnt prevent adding unwanted types Can lead to difficult to troubleshoot issues Runtime errors!
All items are stored as objects
Must be cast going in and coming out Performance overhead of boxing and unboxing specific types
Enforcing Consistent Types
Can control and eliminate unwanted types Create wrapper class for each type
Enforcing Consistent Types
private class BookCollection : CollectionBase { public Book this[ int index ] { get { return (Book) List[index] ;} set { List[index] = value; } }
public int Add( [Link] ) { return [Link](BookNumber); }
public void Remove( [Link] ) { [Link]( BookNumber ); } }
Enforcing Consistent Types
BookCollection bookCol = new BookCollection (); for( int i = 0; i < 20; i++) { [Link]( new Book(i) ); } IEnumerator listEnum = [Link](); while( [Link]() ) { [Link]({0}, ((Book)([Link])).BookNumber); }
Drawbacks
Previous example demonstrated enforcing consistent type use with 1.x Code generators such as CodeSmith can generate wrappers for you Larger code base even if it is by a code generator Still has performance overhead of boxing and unboxing
The Generic Solution
Open constructed types
Classes defined without a specific type Type is specified when instantiated
[Link] namespace
List array dynamically sized as needed Linked list doubly linked list Queue first in, first out collection of objects Stack last in, first out collection of objects
The Generic Solution Continued
Provides type safety at compile time
No loss of performance or code bloat
The .NET CLR recognizes Generics
Only one definition of a parameterized data structure, no matter how many types are used Affects Microsoft Intermediate Language (MSIL)
[Link] Generics Sample 1
Dim testCol As New List(Of int32)() For i as int32 = 0 To 19 [Link](i) Next For each someInt As int32 in testCol [Link]({0}, someInt) Next
C# Generics Sample 1
ArrayList<int> testCol = new ArrayList<int>(); for (int i = 0; i < 20; i++) { [Link](i); } foreach (int someInt in testCol) { [Link]({0}, someInt); }
[Link] Generics Sample 2
Dim bookList As New List(Of Book)() For i as int32 = 0 To 19 [Link](New Book(i)) Next For each book As Book in bookList [Link]({0}, [Link]) Next
C# Generics Sample 2
ArrayList<Book> bookList = new ArrayList<Book>(); for (int i = 0; i < 20; i++) { [Link]( new Book(i) ); } foreach (Book book in bookList) { [Link]({0}, [Link]); }
C++ Templates?
Generics are NOT equal to Templates Compile-Time vs. Run-Time
Templates = Compile-Time Generics = Run-Time
Code Bloat? Pros and Cons for each
Create Your Own Generics
Generics can be applied a number of ways
Classes
Public Class MyType(Of T, U) public class MyType<T,U> {
Method return types and parameters
Public Function Foo() As T public T Foo()
Fields and properties Indexers, properties, events, structs, interfaces, etc.
Example of Create Your Own Generic
public class MyGeneric<T> { private static int objectCount = 0; public MyGeneric() { objectCount++; } public int Count { get { return objectCount; } } public T SomeMethod() }
Example of Create Your Own Generic
Class SomeApplication { static void Main(string[] args) { MyGeneric<int> myIntGeneric = new MyGeneric<int>(); MyGeneric<int> myIntGeneric2 = new MyGeneric<int>(); int someInt = [Link](); MyGeneric<Book> myBookGeneric = new MyGeneric<Book>(); Book someBook = [Link](); [Link]([Link]); [Link]([Link]); [Link]([Link]); [Link](new MyGeneric<Book>().Count); } }
2 2 1 2
Generic Methods
Can overload generic methods
Method signatures can be a challenge Type parameters influence signature Return type does not influence signature Examples
Public List<I> Foo<I, J>(I val1, List<J> val2) {} Public void Foo<K, L>(K val1, List<L> val2) {}
Constraints
Can apply constraints to limit the types used for the type parameter
Public Class MyClass(Of T As {IMyClassA, IMyClassB}) End Class Public class MyClass<T> where T : IMyClassA, IMyClassB { }
Default Values
Assign a default value when the type is not known until implementation
Assigns null for reference types Assigns appropriate default value for built-in types Only available in C# for now
public class MyClass <K, V> { public V Lookup(K key) { V retVal = default(V); return retVal; } }
Nullable Types
Built-in data types such as int dont offer a good way to check if it has been assigned a value [Link]<T> offers a nullable type
Nullable<int> intVal = null; if (![Link]) { [Link]("Is null"); } intVal = 0; if ([Link]) { [Link]("Has value"); }
Power Collections
Open source library of generics [Link] Microsoft support and participation Additional useful types
BigList Deque OrderedDictionary OrderedSet And more
More Information
An Introduction to C# Generics [Link] Generics in .NET: Type Safety, Performance and Generality [Link] Power Collections - [Link] Generics in .NET 2.0 [Link]
Need a Job?
Were Hiring Full Time Employees that have .NET development skills Contact Tara Rodts trodts@[Link]