Introduction:
Question to Mr. C# Corner:
Hello. Mr. C# Corner. I'm Developer, I want to know why you advice me to use Generic instead of Casting Objects and what is the meaning of a Generic?
Answer: One of the important issues in the code development is the [Coding Quality], because your Coding Quality seperates you from other developers. So let us see what are the basics of the coding quality:
- Application Performance.
- Reducing of Casting Object-based data structures.
- Reuse data processing Algorithms (code).
Question to Mr. C# Corner! You say "reduce Casting" of Objects. So what about casting Objects when using Collections (Boxing in general)?
Answer: Ooh...I would like to see the following example which explains the advantage of using generics and how it is more efficient than using non-generic code and how does this matter in coding quality.
Getting Started
What is a Generic: Generics are a new feature in version 2.0 of the C# language and the common language runtime (CLR).
- Generics introduce you to the .NET Framework the concept of type parameters, which makes it possible to design classes, and methods that defer the specification of one or more types until the class or method is declared and instantiated by client code.
- Generics allow you to define type-safe data structures, without committing to actual data types.
Let us see Simple Example about Using and benefits of Generics:
Let us see the difference between a non-generic class and a generic class with your eyes only:
In Figure 1:
Tip!! :
ArrayList is a highly convenient collection class that can be used without modification to store any reference or value type.
Disadvantage of Casting (Boxing)
- Any reference or value type that is added to an ArrayList is implicitly upcast to the Object. If the items are value types, they must be boxed when added to the list, and unboxed when they are retrieved. Both the casting and the boxing and un-boxing operations degrade the code performance; the effect of boxing and un-boxing can be quite significant in scenarios where you must iterate over large collections of data.
- The other limitation is lack of compile-time type checking; since an ArrayList casts everything to Object.
So if you think about generalizing you collection class, what you will do in C# 1.1?
You could avoid the dangers of generalized code in the .NET Framework base class library collection classes by writing your own type specific collections. Of course, since such a class is not reusable for more than one data type, you lose the benefits of generalization, and you have to rewrite the class for each type that will be stored.
In Figure 2:
Let us see what is happen in C# 2.0 to solve these problems:
What ArrayList and other similar classes really need is:
- A way for client code to specify, on a per-instance basis, the particular data type that they intend to use. That would eliminate the need for the upcast to T:System.Object and would also make it possible for the compiler to do type checking. In other words, ArrayList needs a type parameter. That is precisely what generics provide. In the generic List<T> collection, in the N:System.Collections.Generic namespace.
static void GenericTest()
{
// The .NET Framework 2.0 way to create a list
List<int> list1 = new List<int>();
// No boxing, no casting:
list1.Add(3);
// Compile-time error:
// list1.Add("It is raining in Redmond.");
}
For example using a generic type parameter T you can write a single class that other client code can use without incurring the cost or risk of runtime casts or boxing operations.
// Declare the generic class
public class GenericList<T>
{
void Add(T input)
{
}
}
class TestGenericList
{
private class ExampleClass
{
}
static void Main()
{
// Declare a list of type int
GenericList<int> list1 = new GenericList<int>();
// Declare a list of type string
GenericList<string> list2 = new GenericList<string>();
// Declare a list of type ExampleClass
GenericList<ExampleClass> list3 = new GenericList<ExampleClass>();
}
}
Get Started:
The boxing and Un-Boxing:
What is boxing and Un-Boxing in C#?
Boxing a value type packages it inside an instance of the Object reference type.
Boxing Example:
(a) most used Boxing:
int i = 10;
object Obj = i;
(b) It also possible to perform the boxing explicitly as in the following:
int i = 10;
// Casting the value type [ int ] to Object Reference type boxing
object Obj = (object)i;
How Boxing performed?
1- Declare a value-type variable [i] as int
int i = 10;
2- then applies the boxing operation on the variable [i]
object Obj = i;
3- The result of this statement is creating an object reference Obj on the stack.
4- This Object references a value of the type int, on the heap. This value is a copy of the value-type value assigned to the variable [i] which equal 10.
What are the Benefits of this concept?
To allow the value type to be stored on the garbage collected heap.
Un-Boxing Example:
Obj = 10;
// Unboxing extracts the value type from the object Ref Type
i = (int)Obj;
! Disadvantage of Boxing
Boxing and un-Boxing are expensive processes because of the following:
- when a value type is boxed, an entirely new instance object must be allocated and constructed.
- The cast required for un-boxing is also expensive computationally.
Generic is better than using Object based Solution to reducing Object casting Let us see how?
With using Boxing:
readonly int m_Size;
int m_StackPointer = 0;
object[] m_Items;
public void Push(object item)
{
if (m_StackPointer >= m_Size)
throw new StackOverflowException();
m_Items[m_StackPointer] = item;
m_StackPointer++;
}
With using Generic:
readonly int m_Size;
int m_StackPointer = 0;
T[] m_Items;
public void Push(T item)
{
if (m_StackPointer >= m_Size)
throw new StackOverflowException();
m_Items[m_StackPointer] = item;
m_StackPointer++;
}