Performance Guideline: Use Generics To Eliminate the Cost Of Boxing, Casting and Virtual calls
Here's the next .NET Framework 2.0 performance guideline for review from Prashant Bansode, Bhavin Raichura, Girisha Gadikere and Claudio Caldato.
Use Generics To Eliminate the Cost Of Boxing, Casting and Virtual calls
Applies to
- .NET 2.0
What to Do
- Use Generics to eliminate cost of boxing, casting and virtual calls
Why
Generics can be used to improve the performance by avoiding runtime boxing, casting and virtual calls.
List<Object> class gives better performance over ArrayList. An example benchmark of a quick-sort of an array of one million integers may show the generic method is 3 times faster than the non-generic equivalent. This is because boxing of the values is avoided completely. In another example, the quick-sort of an array of one million string references with the generic method was 20 percent faster due to the absence of a need to perform type checking at run time. You results will depend on your scenario. Other benefits of using Generics are compile-time type checking, binary code reuse and clarity of the code.
When
Use Generics feature for defining a code (class, structure, interface, method, or delegate) which has to be used by different consumers with different types.
Consider replacing a generic code (class, structure, interface, method, or delegate), which does an implicit casting of any type to System.Object and forces the consuming code to cast between Object references to actual data types.
Only if there is a considerable number (>500) to store consider having a special class, otherwise just use the default List<Object> class.
List<Object> gives better performance over ArrayList as List<Object> has a better internal implementation for enumeration.
How
The following steps show how to use generics for various types.
Define a generic class as follows.
public class List<T>
Define methods and variables in generic class as follows.
public class List<T>
{
private T[] elements;
private int count;
public void Add(T element)
{
if (count == elements.Length)
Resize(count * 2);
elements[count++] = element;
}
public T this[int index]
{
get { return elements[index]; }
set { elements[index] = value; }
}
}
Access generic class with required type as follows
List<int> intList = new List<int>();
intList.Add(1);
........
int i = intList[0];
Note The .NET Framework 2.0 provides a suite of generic collection classes in the class library. Your applications can further benefit from generics by defining your own generic code
Problem Example
An Order Management Application stores the domain data Item, Price, etc in Cache using ArrayList. ArrayList accepts any type of data and implicitly casts into objects. Numeric data like Order number, customer id, etc are wrapped to object type from primitive types (boxing) while storing in the ArrayList. Consumer code has to explicitly cast the data from Object type to specific data type while retrieving from the ArrayList. Boxing and un-boxing requires lot of operations like memory allocation, memory copy & garbage collection which in turn reduces the performance of the application.
Example code snippet to add items to ArrayList or to get/set items from the ArrayList
ArrayList intList = new ArrayList();
//Cache data in to array
intList.Add(45672); // Argument is boxed
intList.Add(45673); // Argument is boxed
//Retrieve data from cache
int orderId = (int)intList.Item[0]; // Explicit un-boxing & casting required
Solution Example
An Order Management Application stores the domain data Item, Price, etc in Cache. Using Generics feature avoids necessity of run time boxing and casting requirements and makes sure of compile time type checking
Implement the defining code for generic class. Generic class can be implemented only if required, else default List<T> class can be used
//Use to allow consumer code to specify the required type
class OrderList{
//Consumer specific type array to hold the data
T[] elements;
int count;
//No implicit casting while adding to array
public void Add(T element) {
//Add data to array as an object
elements[count++] = element;
}
// Method to set or get data
public T this[int index] {
//Returns data as T type
get { return elements[index]; }
//Set the data as T type
set { elements[index] = value; }
}
}
Initiate the class with specifying as int data type
OrderList intList = new OrderList();
//Cache data in to array
intList.Add(45672); // No boxing required
intList.Add(45673); // No boxing required
//Retrieve data from cache
int orderId = intList[0]; // Un-boxing & casting not required
Additional Resources
- Avoiding Boxing in Classes Implementing Generic Interfaces through Reflection [Dave Fetterman] at https://blogs.msdn.com/bclteam/archive/2005/03/15/396483.aspx.
- Introducing Generics in the CLR at https://msdn.microsoft.com/msdnmag/issues/03/09/NET/
- C# essential Generic syntax at https://msdn.microsoft.com/msdnmag/issues/03/09/NET/