Presentation is loading. Please wait.

Presentation is loading. Please wait.

Introduction to .NET Generics

Similar presentations


Presentation on theme: "Introduction to .NET Generics"— Presentation transcript:

1 Introduction to .NET Generics
Sam Gentile Chief .NET Architect - Adesso July 20, 2004

2 Who is this Guy? Internationally known .NET guy
Working with CLR since 1999! INETA Speaker, MVP – C#/.NET Chief .NET Architect, Adesso Systems .NET products and expertise for Microsoft, Groove, NaviSite, BCGI, Pacific MindWorks Designed and implemented Groove Toolkit for Microsoft Visual Studio .NET (JOLT Winner)

3 Who is this Guy? .NET Writer and Community Blog and Contacts
MSDN Columnist “Beyond Add Reference”, “Using the .NET Framework SDK Interop Tools” WinForms for Managed C++ Programmers, Chris Sells & Sam Gentile, MSDN April 2003 .NET DJ April 2003 Co-author Wrox Visual C++.NET – Interop, COM Interop O’Reilly articles Blog and Contacts Major .NET Blogger at .NET home at

4 Why and What Are Generics?

5 The Need for Generics public class List { private object[] elements;
private int count; public void Add(object element) { if (count == elements.Length) Resize(count * 2); elements[count++] = element; } public object this[int index] { get { return elements[index]; } set { elements[index] = value; } public int Count { get { return count; } public class List<ItemType> { private ItemType[] elements; private int count; public void Add(ItemType element) { if (count == elements.Length) Resize(count * 2); elements[count++] = element; } public ItemType this[int index] { get { return elements[index]; } set { elements[index] = value; } public int Count { get { return count; } List<int> intList = new List<int>(); intList.Add(1); // No boxing intList.Add(2); // No boxing intList.Add("Three"); // Compile-time error int i = intList[0]; // No cast required List intList = new List(); intList.Add(1); intList.Add(2); intList.Add("Three"); int i = (int)intList[0]; List intList = new List(); intList.Add(1); // Argument is boxed intList.Add(2); // Argument is boxed intList.Add("Three"); // Should be an error int i = (int)intList[0]; // Cast required

6 The Need - Unnecessary Boxing and Unboxing

7 Why Generics? Compile-time type checking Binary code reuse Performance
By using ArrayList, we lost type information! Specify & check type at compile time Binary code reuse Reuse same code with multiple types Generic code generated at run-time! CLR reuses most of JIT code Reduced code bloat Performance No boxing and unboxing Clarity Type Checking - When we added an Int to our collection of type List, there is an implicit cast to Object. Similarly, if a int object is retrieved from the list, it must be cast at run time from an Object reference to a int reference. This lack of type safety at compile time is both tedious for the developer and prone to error. In contrast, when we used generics and our List<itemType> where itemType is typed to int causes all add and lookup methods to work with int references. This allows for specifying and checking the type of the elements at compile time rather than at run time. Binary code reuse- For maintenance purposes, a developer may elect to achieve compile-time type safety using List by deriving a StringList from it. The problem with this approach is that new code has to be written for every type for which you want a type-safe list, which can quickly become laborious. With List<T>, all you need to do is instantiate the type with the desired element type as T. As an added value, generics code is generated at run time, so two expansions over unrelated element types such as List<String> and List<FileStream> are able to reuse most of the same just-in-time (JIT)-compiled code. The CLR simply works out the details—no more code bloat! Performance - The bottom line is this: if type checking is done at compile time rather than at run time, performance improves. In managed code, casts between references and values incur both boxings and unboxings, and avoiding such casts can have an equally negative impact on performance. Current benchmarks of a quick-sort of an array of one million integers shows the generic method is three times faster than the non-generic equivalent. This is because boxing of the values is avoided completely. The same sort over an array of string references resulted in a 20 percent improvement in performance with the generic method due to the absence of a need to perform type checking at run time. Clarity – Clarity with generics comes in a number of forms. Constraints are a feature in generics that have the effect of making incompatible expansions of generic code impossible; with generics, you're never faced with the cryptic compiler errors that plague C++ template users. In the GenericSortedList<T> example, the collection class would have a constraint that makes it only work with types for T that can be compared and therefore sorted. Also, generic methods can often be called without employing any special syntax by using a feature called type inference. And, of course, type safety at compile time increases clarity in application code. I will look at constraints, type inference, and type safety in detail throughout this column.

8 What are Generics? Simply, Ability to add parameters to your types
Formally: Parameterized polymorphism of classes, structs, interfaces, delegates & methods by type of data Facility for creating types that have type parameters Looks and feels like template mechanism in C++, Ada, Java but… Don’t suffer their complications, have constraints Operate at runtime versus compile time VB, C#, MC++ produce & consume generics Framework also provides bunch of generic collection classes i.e. System.Collections.Generic.List

9 Terms and Definitions Given example
public class Stack<T> { T[] items; int countItems; public void Push(T item) { ... } public T Pop {....} } Type parameter is T between <> Type parameter formal placeholder for type to be supplied later In Stack<int> stack = new Stack<int>(); int is type argument Stack<int> type called constructed type Process of creating specific constructed type from generic type called generic type instantiation Also called the instance type

10 Applying Generics Generics may have any # of type parameters
Class Node<K, T> { public Node(K key, T item, Node<K, T>nextNode {….} private K Key; private T Item; private Node<k, T> NextNode; } Must then instantiate with the # of parameters

11 Generics in VB VB Dim intList As New List(Of Integer)
Public Class List(Of ItemType)      Private elements() As ItemType      Private elementcount As Integer      Public Sub Add(ByVal element As ItemType)           If elementcount = elements.Length Then Resize(elementcount * 2)           elements(elementcount) = element           count += 1      End Sub      Public Default Property Item(ByVal index As Integer) As ItemType           Get               Return elements(index)           End Get           Set (ByVal Value As ItemType)               elements(index) = Value           End Set      End Property      Public ReadOnly Property Count As Integer               Return elementcount           End Get End Class Dim intList As New List(Of Integer) intList.Add(1)           ‘ No boxing intList.Add(2)           ‘ No boxing intList.Add(“3")     ‘ Compile-time error Dim i As Integer = intList(0)  ’ No cast required

12 Generics in C++ C++ generic<typename T> public ref class List {
   array<T>^ elements;    int count; public:    void Add(T element) {       if (count == elements->Length) Resize(count * 2);       elements[count++] = element;    }    property T default [int index] {       T get() { return elements[index]; }       void set(T value) { elements[index] = value; }    property int Count {       int get() { return count; } }; List<int>^ intList = gcnew List<int>(); intList->Add(1);           // No boxing intList->Add(2);           // No boxing intList->Add(“3");     // Compile-time error int i = intList[0];        // No cast required

13 Type parameters can be applied to
Applying Generics Type parameters can be applied to Class, struct, interface, and delegate types class Dictionary<K,V> {…} struct HashBucket<K,V> {…} interface IComparer<T> {…} delegate R Function<A,R>(A arg); Dictionary<string,Customer> customerLookupTable; Dictionary<string,List<Order>> orderLookupTable; Dictionary<string,int> wordCount;

14 Type parameters can be applied to
Applying Generics Type parameters can be applied to Class, struct, interface, and delegate types Methods string[] names = Utils.CreateArray<string>(3); names[0] = "Jones"; names[1] = "Anderson"; names[2] = "Williams"; Utils.SortArray(names); class Utils { public static T[] CreateArray<T>(int size) { return new T[size]; } public static void SortArray<T>(T[] array) {

15 Demo! Stack Class

16 Applying Generics Generics in a struct Same rules as generic classes
public struct Point<T> { public T x; public T y; } Point<int> point; point.X = 4; point.Y = 2; Point<double> point; point.X = 1.2; point.Y = 4.4; Same rules as generic classes

17 Generic Interfaces public interface ICalculator<T> { T Add(T param1, T param2); } public class SamCalculator : ICalculator<int> public int Add(int arg1, int ar2) { return arg1 + arg2; } Interface declared with type parameters = a generic interface declaration

18 Generic Methods May be declared inside class, struct or interface def, which itself may be generic or non-generic Example of Non-Generic class: public class MyClass { public void MyMethod<T>(T t) {…} } MyClass foo = new MyClass(); Foo.MyMethod<int>(3); Example with class generic: Public delegate bool Test<T>(T item) Public class Finder { public static T Find<T>(T[] items, Test<T> test) { foreach(T item in items) { if (test(item) return item;} throw new InvalidOperationException(“Item not found”); }

19 Constraints

20 Constraints Big problem with C++ templates: try to use method, property of type parameter that it does not implement Causes very confusing unrelated error messages! Unacceptable in CLR as it would break type safety Rule: Generic code is only valid if it will work for every possible constructed instance of the generic Examples: public class Math { public T Min<T>(T item1, T item2) { if (item1 < item2) return item1; return item2; } } What if type T does not have a less-than operator??

21 Constraints public class LinkedList<K, T> { T Find(K key) { …. if (current.Key == key) // will not compile Compiler does not know if K (type supplied) supports == operator Could use IComparable.CompareTo() Does not compile either as compiler has no way of knowing if K derived from IComparable Explicit cast causes exception if not derived and boxing if is In CLR, can tell compiler which constraints a specified type must obey in order to be used instead of generic type parameters Two kinds Derivation constraints Constructor constraints

22 Derivation Constraints
Where reserved word to define a constraint Use where on generic type parameter followed by derivation colon indicating generic type parameter implements particular interface public class LinkedList<K, T> where K : IComparable Does not eliminate boxing penalty Overcome by new generic interface IComparable<T> in System.Collections.Generics Constrain plus new interface eliminates boxing penalty: public class LinkedList<K, T> where K : IComparable<K>

23 Derivation Constraints
All constraints must appear after actual derivation list of generic class Ex: If LinkedList<T> derives from IEnumerable<T>, put where keyword after it: public class LinkedList<K,T> : IEnumerable<T> where K : IComparable<K> In general, only define constraint at level you need it Can provide constraints for every generic type parameter public class LinkedList<K, T> where K : IComparable<K> where T : IClonable

24 Constructor Constraints
Suppose want to instantiate new generic object inside generic class C# compiler doesn’t know whether specific type you are going to use has matching public default constructor Will not compile Constructor constraint makes possible for generic code to create instances of type specified by constraining type args to types that implement public default constructor Only default or parameterless constructors supported

25 Constructor Constraints
class Node<K, T> where T : new() { public Node() Key = default(k); Item = new T(); NextNode = null; }

26 Generics and Casting A variable of a type-parameter type may only be implicitly cast to and from its base constraint type or bases Means If type parameter T has no constraints can only be cast to and from System.Object static void Foo<T>(T arg) { Object o = arg; T temp = (T) o; Int32 num; num = (Int32) temp; // Compiler error num = (Int32)(Object) temp;// Compiles, but throws InvalidCast // Exception at runtime if T!=Int temp = (T) 5; // Compiler Error temp = (T) (Object) 5; // Compiles, but throws

27 Iterators Recall foreach is used to iterate over elements of an enumerable collection To be enumerable, collection must have parameterless GetEnumerator method returning an enumerator C# 2.0 simplifies creating enumerators with Iterators Iterator is statement block that yields an ordered seq. of values Distinguished from normal statement block by presence of one or more yield statements The yield return statement produces next value of iteration The yield break statement indicates iteration complete Iterator may be used as body of function member as long as return type of function member one of enumerator interfaces or enumerable interfaces

28 Iterators The enumerator interfaces are System.Collections.IEnumerator and types constructed from System.Collections.Generic.IEnumerator<T> The enumerable interfaces are System.Collections.IEnumerable and types constructed from System.Collections.Generic.IEnumerable<T> Note! Iterator not kind of member but means of implementing a function member Member implemented via Iterator may be overridden or overloaded by other members that may or may not be implemented via Iterators Using System.Collections.Generic; Public class Stack<T> : IEnumerable<T> { T[] items; int count; public void Push(T data) {….} public IEnumerator<T> GetEnumerator() { for (int I = count – 1; I >= 0; --i) { yield return items[i]; }

29 Constraints, Iterators in a Linked List Class
Demo! Constraints, Iterators in a Linked List Class

30 Using Generics in the BCL

31 Enhancing the Base Library Generic Collections
System.Collections.Generic classes List<T> LinkedList<T> // new in Beta1! Dictionary<K, V> // equivalent to non-generic HashTable Stack<T> Queue<T> System.Collections.Generic interfaces IList<T> // replacement for IList IDictionary<K, V> // replacement for IDictionary ICollection<T> // replacement for ICollection IEnumerable<T> // replacement for IEnumerable IEnumerator<T> // replacement for IEnumerator IComparable<T> // replacement for IComparable IComparer<T> // replacement for IComparer

32 Using Generics in the BCL
All generic collections implement generic IEnumerable<T> interface IEnumerable<T> provides access to IEnumerator<T> Iterators interface, for abstracted iterations over collections (Think C++ STL Iterators) Public interface IEnumerable<T> { IEnumerator<T> GetEnumerator(); } Public interface IEnumerator<T> : IDisposable { T Current {get;} bool MoveNext(); }

33 System.Nullable<T>
Provides nullability for any type Useful in many situations such as nullable columns in database Struct that combines a T and a bool Conversions between T and Nullable<T> Conversion from null literal to Nullable<T> Nullable<int> x = 123; Nullable<int> y = null; int i = (int)x; int j = x.Value; if (x.HasValue) Console.WriteLine(x.Value);

34 Using the New Generic BCL Collection Classes
Demo! Using the New Generic BCL Collection Classes

35 CLR Implementation of Generics

36 Differences with C++ Templates
Generics not same as C++ templates! C++ templates With many C++ compilers, compiler does not even compile until use with type When type specified, compiler inserts inline – global find and replace! Compiler inserts every time even if already specified that type Up to linker to resolve if can Code bloating Cryptic error messages!

37 Generics Implementation in CLR
Research & Prototype with Gyro in Rotor After paper in 2001 Design takes into account dynamic loading & code generation of CLR Generics have native support in IL and CLR Thus a multi-language design Design Features “Just-in-time” type specialization Code and representation sharing No boxing Efficient support of run-time types

38 Generics Implementation in CLR
Support for Polymorphism in IL Some new types added to IL type system New polymorphic forms of IL declarations for classes, interfaces, structs, methods Some new IL instructions and generalizations of existing ones

39 Non-Generic Stack IL .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code Size: 29 byte(s) .maxstack 8 L_0000: ldarg.0 L_0001: call instance void object::.ctor() L_0006: nop L_0007: ldarg.0 L_0008: ldc.i4.s 10 L_000a: newarr object L_000f: stfld object[] Stack::store L_0014: ldarg.0 L_0015: ldc.i4.0 L_0016: stfld int32 Stack::size L_001b: nop L_001c: ret }

40 Generic Stack IL .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code Size: 29 byte(s) .maxstack 8 L_0000: ldarg.0 L_0001: call instance void object::.ctor() L_0006: nop L_0007: ldarg.0 L_0008: ldc.i4.s 10 L_000a: newarr !0 L_000f: stfld !0[] Stack!1<!0>::store L_0014: ldarg.0 L_0015: ldc.i4.0 L_0016: stfld int32 Stack!1<!0>::size L_001b: nop L_001c: ret }

41 JIT Compilation of Generic IL
Code with generics still compiled to IL But, IL contains parameters/placeholders for actual specific type Plus metadata contains generic info Depends on whether value or reference type If value type, JIT replaces generic type parameters in IL with specific value + compiles BUT, JIT keeps track of type-specific code already generated If same type, simply returns reference – shared No code bloating!

42 References The C# Programming Language, Hejlsberg, Wiltamuth & Golde, AW, 2004 “The Design and Implementation of Generics for the .NET Common Language Runtime”, Kennedy and Syme, Microsoft Research “Introducing Generics in the CLR”, MSDN Magazine, September 2003, “More on Generics in the CLR”, October 2003, My CLR/Rotor Blog

43 It’s A User Group Thing As an INETA member, your User Group gets:
Visits from Speaker Bureau members at no charge INETA even pays for the pizza Discounts on software, conferences, subscriptions and more Newsletter, content repository and forums of use to User Group members INETA needs volunteers Benefit your User Group and yourself by getting involved INETA Web Site:


Download ppt "Introduction to .NET Generics"

Similar presentations


Ads by Google