Application security

Generics

March 4, 2013 by Ajay Yadav

Introduction

Generics cater many of the benefits of strongly typed collections as well as provide higher quality and performance boost code. Generics are very similar to C++ templates but having a slight difference in such a way that the source code of C++ templates is required when a templates is instantiated with a specific type and .NET Generics are not limited to classes only. In fact, they can also be implemented with Interface, Delegates and Methods. The detailed specification for each collection is found under the System.Collection.Generic namespace.

Boxing and Unboxing

.Net defines two major categories of data type termed value type and reference type to represent a variable. This is where boxing and unboxing come into light. Boxing is a mechanism to explicitly convert value type to reference type by storing the variable into System.Object; when you ‘box’ the value, the CLR allocates a new object into the heap and copies the value type’s value into that instance. For example, you have created a variable of int type, like this:

int a = 20;

object b = a; //boxing

The opposite operation is called Unboxing, which is the process of converting back the reference type into the value type. This process verifies that the receiving data type is equivalent to the boxed type:

int c = (int)b; // unboxing

The C# compiler notices assignments from int to object and vice-versa. When this program is compiled and you examine the IL generated code via the IL dissembler,you notice that the program responds by inserting a box instruction in the IL automatically when b is assigned the value of a and an unbox instruction when c is assigned the value b, as following:

Figure 1.1 – IL opcode

Figure 1.1 – IL opcode

The code loads the constant 20 and stores it in the local slot; it the loads the value 20 onto the stack and boxes it. Finally, it loads the boxed 20 back onto the stack and unboxes it into an int.

There are series of operations performed by .NET CLR, such as First an object allocated into managed heap, then in boxing, the value transformed into the memory location and during unboxing, the value stored on the heap must be transferred back to the stack. So the Boxing and Unboxing process has a significant importance in Generic from the performance point of view because this process is more resource intensive compared to using Generics.

Generic Classes

The Generic class can be defined by putting the sign after the class name. However, It isn’t mandatory to put the ‘T’ word in the Generic type definition. You can mention any word in the TestClass<> class declaration.

publicclassTestClass { }

The System.Collection.Generic namespace also defines a number of classes that implement many of these key interfaces. The following table describes the core class types of this namespace:

Non-Generics Members Description
Collection The basis for a generic collection

Comparer Compares two generic objects for

EqualityDictionary A generic collection of

name/value pairsList A dynamically resizable list of

ItemsQueue A generic implementation of a

first-in, first-out (FIFO) listStack
A generic implementation of a

last-in, first-out (LIFO) list

Simple Generic Class Example

The following example showcases simple Generic type manipulation. The TestClass defines an array of generic type with length 5. The Add() method is responsible for adding any type of objects into the collection and The Indexer property is an implementation for the foreach statement iteration. Finally, in the main class, we instantiated the TestClass class with Integer type reference and added some integer types elements into the collection using the Add() method.

using System;

usingSystem.Collections.Generic;

namespaceGenericApp

{

publicclassTestClass

{

// define an Array of Generic typewith length 5

T[] obj = new T[5];

int count = 0;

// adding items mechanism into generic type

publicvoid Add(T item)

{

//checking length

if (count + 1 < 6)

{

obj[count] = item;

}

count++;

}

//indexer for foreach statement iteration

public T this[int index]

{

get { returnobj[index]; }

set { obj[index] = value; }

}

}

classProgram

{

staticvoid Main(string[] args)

{

//instantiate generic with Integer

TestClass<int>intObj = newTestClass<int>();

//adding integer values into collection

intObj.Add(1);

intObj.Add(2);

intObj.Add(3); //No boxing

intObj.Add(4);

intObj.Add(5);

//displaying values

for (inti = 0; i< 5; i++)

{

Console.WriteLine(intObj[i]); //No unboxing

}

Console.ReadKey();

}

}

}

After the build-up and execution of this program, the output is as follows:

Figure 1.2 – Simple Generic Example

Figure 1.2 – Simple Generic Example

There are some significant characteristics of Generic types that make it special to the conventional non-generics type, as following:

  • Type Safety
  • Performance
  • Binary Code reuse

Type Safety

One of the most significant features of Generic is Type Safety. In the case of the ArrayList class, if objects are used, any type can be added to the collections, which can lead to a great disaster. The following example has it adding an integer, string and object to the collection of the ArrayList type:

ArrayListobj = newArrayList();

obj.Add(50);

obj.Add(“Dog”);

obj.Add(newTestClass());

Now, if the collection is iterated through the foreach statement using integer elements, the compiler accepts the code; but because all the elements in the collection are not integer, a runtime exception occurs:

foreach(intiinobj)

{

Console.WriteLine(i);

}

The rule of thumb in programming is that errors should be detected as early as possible. With the generic class Test, the generic type T defines what types are allowed. With the definition of Test, only integer types can be added into the collection. The compiler doesn’t compile the code because the Add() method has invalid arguments, as you can see:

Test<int>obj = new Test<int>();

obj.Add(50);

obj.Add(“Dog”); //compiler error

obj.Add(newTestClass()); //compiler error

Performance

Another feature of Generic is performance. Using value types with non-generic collection classes results in boxing and unboxing overhead when a value type is converted to reference type and vice-versa.

In the following example, the ArrayList class stores objects and the Add() method is defined to store some integer type argument. So an integer type is boxed. When the value from ArrayList is read using the foreach statement, unboxing occurs.

ArrayListobj = newArrayList();

obj.Add(50); //boxing- convert value type to reference type

int x= (int)obj[0]; //unboxing

foreach(intiinobj)

{

Console.WriteLine(i); // unboxing

}

Note: Generics are faster than other collections such as ArrayList.

Instead of using objects, Generics type of the TestClass class are defined as int; so the int type is used inside the class that generated dynamically from the compiler. Therefore, boxing and unboxing no longer happens, as seen below:

TestClass<int>obj = newTestClass<int>();

obj.Add(50); //No boxing

int x= obj[0]; // No unboxing

foreach(intiinobj)

{

Console.WriteLine(i); //No unboxing

}

Binary Code reuse

Generic provides a kind of source code protection. A Generic class can be defined once and can be instantiated with many different types. Generics can be defined in one CLR supported language and used from other any other .NET language. The following TestClass is instantiated with an int, string types.

TestClass<int>obj = newTestClass<int>();

obj.Add(50);

TestClass<string> obj1 = newTestClass<string>();

Obj1.Add(“hello”);

Generic Methods

While most developers will typically make use of the existing generic types within the base class libraries, it is certainly possible to build your own generic members and custom generic types.

The objective of this example is to build a swap method that can operate on any possible data type (value-based or reference-based) using a single type parameter. Due to the nature of swapping algorithms, the incoming parameters will be sent by reference via the ref keyword.

using System;

usingSystem.Collections.Generic;

namespaceGenericApp

{

classProgram

{

//Generic method

staticvoid Swap(ref T a, ref T b)

{

T temp;

temp = a;

a = b;

b = temp;

}

staticvoid Main(string[] args)

{

// Swap of two integers.

int a = 40, b = 60;

Console.WriteLine(“Before swap: {0}, {1}”, a, b);

Swap<int>(ref a, ref b);

Console.WriteLine(“After swap: {0}, {1}”, a, b);

Console.ReadLine();

}

}

}

After compiling this Generic method implementation program, the output will look something like this:

Figure 1.3 – Generic Methods

Figure 1.3 – Generic Methods

Dictionary

Dictionaries, also known as maps or hash tables, represent a data structure that allows you to access an element based on a key. One of the significant features of dictionaries is faster lookup; you can add or remove items without the performance overhead.

.NET offers several dictionary classes for instance Dictionary. The type parameters TKey and TValue represent the type of the keys and value it can store respectively.

Simple Example of Dictionary

The following example demonstrates simple dictionary collections using Generics. In this program, a Dictionary type object is created which accepts int as a key and string as a value. Then we add some string values into the dictionary collection and finally display the dictionary collection elements.

Using System;

usingSystem.Collections.Generic;

namespaceGenericApp

{

publicclassProgram

{

staticvoid Main(string[] args)

{

//define Dictionary collection

Dictionary<int,string>dObj = newDictionary<int,string>(5);

//add elements to Dictionary

dObj.Add(1,“Tom”);

dObj.Add(2,“John”);

dObj.Add(3, “Maria”);

dObj.Add(4, “Max”);

dObj.Add(5, “Ram”);

//print data

for (inti = 1; i

{

Console.WriteLine(dObj[i]);

}

Console.ReadKey();

}

}

}

The following example portrays some of more complexities involved with defining an addition class emp, where we are overriding the ToString() method to display the name and salary of a particular employees. Later, in the Main() method, a new Dictionary string and the value is of type emp. The constructor allocates a capacity of 2 elements. The emp objects and string value as a key are added to the dictionary collection. Finally, the collection elements are iterated using the foreach statement and displayed on the screen.

using System;

usingSystem.Text;

usingSystem.Collections.Generic;

namespaceGenericApp

{

publicclassemp

{

privatestring name;

privateint salary;

publicemp(stringname,int salary)

{

this.name = name;

this.salary = salary;

}

publicoverridestringToString()

{

StringBuildersb = newStringBuilder(200);

sb.AppendFormat(“{0},{1}”,name,salary);

returnsb.ToString();

}

}

publicclassProgram

{

staticvoid Main(string[] args)

{

//define Dictionary collection

Dictionary<string, emp>dObj = newDictionary<string, emp>(2);

//add elements to Dictionary

emp tom = newemp(“tom”, 2000);

dObj.Add(“tom”,tom); // key,value

emp john = newemp(“john”, 4000);

dObj.Add(“john”,john);

//print data

foreach(ObjectstrindObj.Values)

{

Console.WriteLine(str);

}

Console.ReadKey();

}

}

}

Queues

Queues are special type of container that ensures the items are being accessed in the FIFO (first in, first out) manner. Queues collections are most appropriate for implementing messaging components. We can define a Queue collection object via the following syntax:

QueueqObj = newQueue();

The Queue collection property, methods and other specification definitions are found under the Sysyem.Collection namespace. The following table defines the key members:

System.Collection.Queue Members Definition
Enqueue() Add an object to the end of the queue.
Dequeue() Removes an object from the beginning of the queue.
Peek() Return the object at the beginning of the queue without removing it.

The following demonstrate a basic Queues type collection, adds some string type values into the collection and finally displays the entire items into the collection using the while statement.

Using System;

usingSystem.Collections;

namespaceGenericApp

{

classProgram

{

staticvoid Main(string[] args)

{

//Defines a Queue.

QueueqObj = newQueue();

//adding string values into collection

qObj.Enqueue(“Tom”);

qObj.Enqueue(“Harry”);

qObj.Enqueue(“Maria”);

qObj.Enqueue(“john”);

//displaying collections

while(qObj.Count !=0 )

{

Console.WriteLine(qObj.Dequeue());

}

Console.ReadKey();

}

}

}

Stacks

A Stack collection is an abstraction of LIFO (last in, first out). We can define a Stack collection object via the following syntax:

StackqObj = newStack();

The following table illustrates the key members of stack:

System.Collection.Stack Members Definition
Contains() Return true if a specific element is found in the collection.
Clear() Removes all the elements of the collection.
Peek() Preview the most recent element on the stack.
Push() It pushes elements into the stack.
Pop() Return and remove the top elements of the stack.

The following code demonstrates a stack collection. First, an array type object is referenced into the stack collection. Then the value of the elements in the collection are removed from the stack using the Pop() method and displayed on the screen.

using System;

usingSystem.Collections;

namespaceGenericApp

{

classProgram

{

staticvoid Main(string[] args)

{

int[] iArray = newint[] {1,2,3,4,5,6,7,8,9,10 };

//Define a stack

StacksObj = newStack(iArray);

Console.WriteLine(“Total items=”+sObj.Count);

//displaying collections

for (inti = 0; i

{

Console.WriteLine(sObj.Pop());

}

Console.ReadKey();

}

}

}

In an another example with Generic implementation, 5 items are added to the stack with the Push() method. With the foreach statement, all of the items are iterated using the IEnumerable interface. The enumerator of the stack does not remove the items; it just returns them item by item in LIFO manner, as following;

using System;

usingSystem.Collections.Generic;

namespaceGenericApp

{

publicclassProgram

{

staticvoid Main(string[] args)

{

//define Dictionary collection

Dictionary<int,string>dObj = newDictionary<int,string>(5);

//add elements to Dictionary

dObj.Add(1,“Tom”);

dObj.Add(2,“John”);

dObj.Add(3, “Maria”);

dObj.Add(4, “Max”);

dObj.Add(5, “Ram”);

//print data

foreach(stringiindObj.Values)

{

Console.WriteLine(i);

}

Console.ReadKey();

}

}

}


Posted: March 4, 2013
Ajay Yadav
View Profile

Ajay Yadav is an author, Cyber Security Specialist, SME, Software Engineer, and System Programmer with more than eight years of work experience. He earned a Master and Bachelor Degree in Computer Science, along with abundant premier professional certifications. For several years, he has been researching Reverse Engineering, Secure Source Coding, Advance Software Debugging, Vulnerability Assessment, System Programming and Exploit Development. He is a regular contributor to programming journal and assistance developer community with blogs, research articles, tutorials, training material and books on sophisticated technology. His spare time activity includes tourism, movies and meditation. He can be reached at om.ajay007[at]gmail[dot]com