dotnetspider.com
Login Login    Register      

TutorialsForumCareer DevelopmentResourcesReviewsJobsInterviewCommunitiesProjectsTraining

Subscribe to Subscribers
Talk to Webmaster
Tony John

Facebook
Google+
Twitter
LinkedIn
Online Membersbaskar
More...
Join our online Google+ community for Bloggers, Content Writers and Webmasters




Resources » .NET programming » ASP.NET/Web Applications

Basic Funda of Generics in C#


Posted Date:     Category: ASP.NET/Web Applications    
Author: Member Level: Gold    Points: 10


This article is basically points to Generics fundamental in C#.net



 


In C# there is two types of mechanism for writing code that is reusable across different type.
1)Inheritance
2)Generic.

Inheritance express reusability across base type,while generic express reusability with a template that contains placeholder.

Mainly Generics used for type safety and reducing casting and boxing.

Now first glance on Generic Types.

A generic type declares generic parameters—placeholder types to be filled in by the consumer of the generic type, who will supply the generic arguments. Here is a generic type Stack<T>, designed to stack instances of type T. Stack<T> declares a single generic parameter T:


public class Stack<T>
{
int position;
T[] data = new T[100];
public void Push (T obj) { data[position++] = obj; }
public T Pop() { return data[--position]; }
}


We can use Stack<T> as follows:

Stack <int> stack = new Stack <int> ();
stack. Push(5);
stack. Push(10);
int x = stack.Pop(); // x is 10
int y = stack.Pop(); // y is 5


Stack<int> fills in the generic parameter T with the generic argument int, implicitly creating a type on the fly (the synthesis occurs at runtime). Stack effectively has the following definition (substitutions appear in bold, with the class name hashed out to avoid confusion):

public class ###
{
int position;
int[] data;
public void Push (int obj) { data[position++] = obj; }
public int Pop() { return data[--position];}
}


Technically, we say that Stack<T> is an open type, whereas Stack<int> is a closed type. You can only instantiate a closed type, because all the placeholder types must be filled in.

Why generics exist?

Different types of generic code that is reusable for writing exist. Let's say we need a stack of integers, but we did not have normal type. All the necessary elements for a solution (eg, IntStack, StringStack, etc.) Clearly, this type of code duplication would cause quite a different version of the class will hardcode. Another solution is to write a stack object by using the element type as would be generalized:


public class ObjectStack
{
int position;
object[] data = new object[10];
public void Push (object obj){data[position++] = obj;}
public object Pop() { return data[--position];}
}


An ObjectStack, however, wouldn't work as well as a hardcoded IntStack for specifically stacking integers. Specifically, an ObjectStack would require boxing and downcasting that could not be checked at compile time:


// Suppose we just want to store integers here:
ObjectStack stack = new ObjectStack();

stack.Push ("s"); // Wrong type, but no error!
int i = (int)stack.Pop(); // Downcast - runtime error


What we need is both a general implementation of a stack that works for all element types, and a way to easily specialize that stack to a specific element type for increased type safety and reduced casting and boxing. Generics give us precisely this, by allowing us to parameterize the element type. Stack has the benefits of both ObjectStack and IntStack. Like ObjectStack, Stack is written once to work generally across all types. Like IntStack, Stack is specialized for a particular type—the beauty is that this type is T, which we substitute on the fly.


Generic Method



A generic method declares generic parameters within the signature of a method.

With generic methods, many fundamental algorithms can be implemented in only a general-purpose way. Here is a generic method that swaps two values of any type:


static void Swap<T> (ref T a, ref T b)
{
T temp = a; a = b; b = temp;
}


Swap<T> can be used as follows:

int x = 5, y = 10;
Swap (ref x, ref y);


Generally, there is no need to supply type parameters to a generic method, because the compiler can implicitly infer the type. If there is ambiguity, generic methods can be called with the type parameters as follows:


Swap<int> (ref x, ref y);


Within a generic type, a method is not classed as generic unless it introduces generic parameters (with the angle bracket syntax). The Pop method in our generic stack merely uses the type's existing generic parameter, T, and is not classed as a generic method.

Methods and types are the only constructs that can introduce generic parameters. Properties, indexers, events, fields, methods, operators, and so on cannot declare generic parameters, although they can partake in any generic parameters already declared by their enclosing type. In our generic stack example, for instance, we could write an indexer that returns a generic item:


public T this [int index] { get {return data [index];} }


Declaring Generic Parameters



Generic parameters can be introduced in the declaration of classes, structs, interfaces, delegates (see the upcoming "Delegates" section), and methods. Other constructs, such as properties, cannot introduce a generic parameter, but can use a generic parameter. For example, the property Value uses T:


public struct Nullable<T>
{
public T Value {get;}
}


A generic type or method can have multiple parameters. For example:

class Dictionary<TKeyType, TValueType> {...}


To instantiate:

Dictionary<int,string> myDic = new Dictionary<int,string>();
var myDic = new Dictionary<int,string>();

Generic type names and method names can be overloaded as long as the number of generic parameters is different. For example, the following two type names do not conflict:


class A<T> {}
class A<T1,T2> {}


<H2>typeof and Generics</H2>

The typeof operator requires specifying the number of parameters when asking for the type of an open type, as follows:


class A<T> {}
class A<T1,T2> {}
...

Type a1 = typeof(A<>);
Type a2 = typeof(A<,>);


Here is an example of asking for the type of a closed type:

Type a3 = typeof(A<int,int>);

The default Generic Value



The default keyword can be used to get the default value given a generic type argument. The default value for a reference type is null, and the default value for a value type is the result of bitwise-zeroing the value type's fields:

static void Zap<T> (T[] array)
{
for (int i = 0; i < array.Length; i++)
array[i] = default(T);
}



Generic Constraints



By default, a generic parameter can be substituted with any type whatsoever. Constraints can be applied to a generic parameter to require more specific type arguments. These are the possible constraints:

where T : base-class // Base class constraint
where T : interface // Interface constraint
where T: class // Class constraint
where T : struct // Struct constraint
where T : new() // Parameterless constructor
// constraint
where U : T // Naked type constraint


In the following example, GenericClass<T> requires T to derive from SomeClass and implement Interface1:


class SomeClass {}
interface Interface1 {}

class GenericClass<T> where T : SomeClass, Interface1 {}


Constraints can be applied wherever generic parameters are defined, in both methods and type definitions.

A base class constaint or interface constraint specifies that the type parameter must subclass or implement a particular class or interface. This allows instances of that type to be implicitly cast to that class or interface. For example, suppose we want to write a generic Max method that returns the maximum of two values. We can take advantage of the generic interface defined in the System namespace IComparable<T>:


public interface IComparable<T>
{
int CompareTo (T other);
}


CompareTo returns a positive number if other is greater than this. Using this interface as a constraint, we can write a Max method as follows (to avoid distraction, null checking is omitted):


static T Max <T> (T a, T b) where T : IComparable<T>
{
return a.CompareTo (b) > 0 ? a : b;
}


The Max method can accept arguments of any type implementing IComparable<T> (which includes most built-in types such as int and string):

int z = Max (5, 10); // 10
string last = Max ("ant", "zoo"); // zoo


The class constraint and struct constraint simply specify that T must be a class or a struct. A great example of the struct constraint is the System.Nullable<T> struct (we will discuss this class in depth, later, in the "Nullable Types" section):

struct Nullable<T> where T : struct {...}

The parameterless constructor constraint requires T to have a public parameterless constructor. If this constraint is defined, you can call new() on T:


static void Initialize<T> (T[] array) where T : new()
{
for (int i = 0; i < array.Length; i++)
array[i] = new T();
}


The naked type constraint requires one generic parameter to derive from another generic parameter. In this example, the method FilteredStack returns another Stack, containing only the subset of elements where the generic parameter T is of the generic parameter U:

class Stack<T>
{
Stack<U> FilteredStack<U>() where U : T {...}
}

Generics and Covariance



Generic types are not covariant. This means that even if B can be cast to A, T<B> cannot be cast to T<A>. For example, suppose Animal and Bear are defined as follows:

class Animal {}
class Bear : Animal {}

The following is illegal:

Stack<Bear> bears = new Stack <Bear>();

// compile-time error
Stack<Animal> animals = bears;


Lack of covariance can hinder reusability. Suppose, for instance, we wanted to write a method to Wash a stack of animals:


public class ZooCleaner
{
public static void Wash (Stack<Animal> animals) {...}
}


Calling Wash with a stack of bears would generate a compile-time error. The workaround is to redefine the Wash method with a constraint:


public class ZooCleaner
{
public static void Wash<T> (Stack<T> animals)
where T : Animal {}
}


We can now call Wash as follows:

Stack<Bear> bears = new Stack<Bear>();
ZooCleaner.Wash (bears);


Subclassing Generic Types


A generic class can be subclassed just like a nongeneric class. The subclass can leave the base class's generic parameters open, as in the following example:


class Stack <T> {...}
class SpecialStack <T> : Stack <T> {...}


Or the subclass can close the generic type parameters with a concrete type:

class IntStack : Stack<int> { ... }


A subclass can also introduce fresh generic arguments:

class Single<T> { ... }
class Double<T,U> : Single<T> { ... }


Self-Referencing Generic Declarations


A type can name itself as the concrete type when closing a generic argument:


public interface IEquatable<T> { bool Equals (T obj); }

public class Balloon : IEquatable<Balloon>
{
string color;
int cc;

public bool Equals (Balloon b)
{
if (b == null) return false;
return b.color == color && b.cc == cc;
}
}


Static Data



Static data is unique for each closed type:


class Bob<T> { public static int Count; }

class Test
{
static void Main()
{
Console.WriteLine (++Bob<int>.Count); // 1
Console.WriteLine (++Bob<int>.Count); // 2
Console.WriteLine (++Bob<string>.Count); // 1
Console.WriteLine (++Bob<object>.Count); // 1
}
}
}


Generic Collection Initialization



You can instantiate and populate a generic collection in a single step, as follows:

using System.Collections.Generic;
...
List<int> list = new List<int> {1, 2, 3};

The compiler translates this to:

using System.Collections.Generic;
...

List<int> list = new List<int>();
list.Add (1); list.Add (2); list.Add (3);


This requires that the collection implements the ICollection<T> interface, defined in System.Collections.Generic—the standard .NET interface for mutable collections.





Did you like this resource? Share it with your friends and show your love!


Responses to "Basic Funda of Generics in C#"

No responses found. Be the first to respond...

Feedbacks      

Post Comment:




  • Do not include your name, "with regards" etc in the comment. Write detailed comment, relevant to the topic.
  • No HTML formatting and links to other web sites are allowed.
  • This is a strictly moderated site. Absolutely no spam allowed.
  • Name:   Sign In to fill automatically.
    Email: (Will not be published, but required to validate comment)



    Type the numbers and letters shown on the left.


    Next Resource: Personalization in ASP.NET 2.0
    Previous Resource: Namespace in C#
    Return to Resources
    Post New Resource
    Category: ASP.NET/Web Applications


    Post resources and earn money!
     
    More Resources
    Popular Tags   Tag posting guidelines   Search Tags  
    Generics  .  Basic Funda  .  



    Follow us on Twitter: https://twitter.com/dotnetspider

    Active Members
    TodayLast 7 Daysmore...

    Awards & Gifts
    Email subscription
  • .NET Jobs
  • .NET Articles
  • .NET Forums
  • Articles Rss Feeds
    Forum Rss Feeds


    About Us    Contact Us    Copyright    Privacy Policy    Terms Of Use    Revenue Sharing sites   Advertise   Talk to Tony John
    Copyright © SpiderWorks Technologies Pvt Ltd., Kochi, India
    2005 - 2012 All Rights Reserved.
    .NET and other trademarks mentioned in this site belong to Microsoft and other respective trademark owners.
    Articles, tutorials and all other content offered here is for educational purpose only.
    We are not associated with Microsoft or its partners.