博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Generics in C#2.0

Posted on 2006-07-28 11:04  james.dong  阅读(206)  评论(0)    收藏  举报

来自:http://www.csharphelp.com/archives4/archive658.html
Generics in C# 2.0 - Part I

By Saurabh Mishra

Generics are new feature provided with version 2.0 of the Microsoft.Net framework. Generic classes and methods combine re-usability, type safety and efficiency in a way that there non-generics counterparts do not/cannot.

In this part some features of ArrayLists and there shortcomings/limitations will be discussed. The contained in this article has been written in Visual Studio 2005 in C#.

Earlier ArrayLists used to server the purpose, but that in a certain limit. Moreover, using ArrayLists to store different types came as a good performance cost. At the client end it our desired type that we are storing in the ArrayList but internally there's much more that goes on.

Sample the code below:-
System.Collections.ArrayList myList = new System.Collections.ArrayList ();
myList.Add (22);
myList.Add ("C# Generics");
myList.Add (22.45);

The usage convenience that is perceived above comes at a cost. Any reference or value type that is stored or added in the ArrayList (myList) is implicitly upcasted to System.Object type. And while retrieval, the reverse happens - downcasting to the appropriate type takes place.

Moreover, there is compromise on the Type Safety front also. Consider the code below:-

int item =0;
//This will cause an InvalidCastException
foreach (int x in myList)
{
Item = item+x;
}

The reason is evident.

In .Net 1.x type-safety was achieved by writing your own typed ArrayList. But again, in that case re-usability was a major issue. Consider the following code:-

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace ArrayListSample
{
#region Person Class
class Person
{
String Name;
Int32 Age;
String Address;
#region Constructor
public Person() { }
public Person(String Name, Int32 Age, String Address)
{
Name = Name;
Age = Age;
Address = Address;
}
public Person(String Name, Int32 Age)
{
Name = Name;
Age = Age;
Address = String.Empty;
}
public Person(String Name, String Address)
{
Name = Name;
Age = 0;
Address = Address;
}
public Person(String Name)
{
Name = Name;
Age = 0;
Address = String.Empty;
}
#endregion
}
#endregion
#region PeopleCollection Class
class PeopleCollection : System.Collections.IEnumerable
{
private ArrayList arPeople = new ArrayList();
public PeopleCollection()
{
}
#region Methods
public void AddPeople(Person p)
{
arPeople.Add(p);
}
public void ClearPeople()
{
arPeople.Clear();
}
int Count;
public int PeopleCount
{
get { return Count; }
}
#endregion
#region IEnumerable Members
public System.Collections.IEnumerator GetEnumerator()
{
return arPeople.GetEnumerator();
}
#endregion
}
#endregion
class Client
{
public static void Main()
{
PeopleCollection myPeople = new PeopleCollection();
myPeople.AddPeople(new Person("Saurabh",24,"Gurgaon"));
myPeople.AddPeople(new Person("Manu"));
foreach (Person Person in myPeople)
{
Console.WriteLine(Person);
}
Console.ReadLine();
}
}
}

The above code does achieve type safety but then we will have to write an almost identical custom collection for each type we wish to contain. Because:-

myPeople.AddPeople(new Car());

would be a compile time error, since the code/approach above achieves type safety. So at the end of the day it will be a big nightmare !!

So above we find some of the limitations of ArrayLists. In the next issue we will find how Genrics solve the issues discussed above.


Generics in C#2.0 - Part II

By Saurabh Mishra

In my last article I focused on issues of type safety and reusability when using ArrayLists. In this article we shall focus on how these issues of type safety and reusability are very nicely handled by Generics. All with the help of code again :

using System;
using System.Collections.Generic;
using System.Text;
namespace GenericsSample
{
class Person
{
int _Age;
public int Age
{
get { return _Age; }
set { _Age = value; }
}
String _Name;
public String Name
{
get { return _Name; }
set { _Name = value; }
}
String _Address;
public String Address
{
get { return _Address; }
set { _Address = value; }
}
String _Company;
public String Company
{
get { return _Company; }
set { _Company = value; }
}
public Person() { }
public Person(String Name)
{
this.Name = Name;
this.Age = 0;
this.Address = String.Empty;
this.Company = String.Empty;
}
public Person(String Name, int Age, String Address)
{
this.Name = Name;
this.Age = Age;
this.Address = Address;
}
}
class Program
{
static void Main(string[] args)
{
//Generic List Creation
//List is a Generic Class provided by .Net Framework 2.0
//System.Collections.Generics is the Namespace.
List
 myPerson = new List
();
myPerson.Add(new Person("Saurabh"));
myPerson.Add(new Person("Manu"));
myPerson.Add(new Person("SomeOne", 24, "Gurgaon"));
myPerson.Add(new Person("SomeoneElse", 24, "Gurgaon"));
//myPerson.Add(new Car());// This is A Compile Time Error
foreach (Person p in myPerson)
{
Console.WriteLine(p.Name);
Console.WriteLine(p.Age);
Console.WriteLine(p.Address);
Console.WriteLine(p.Company);
}
Console.ReadLine();
}
}
}
Two classes can be seen in this code. Class Person is the class of which we want to create list for, and class Program is the main class where we actually create the list of persons and operate upon them.

How Generics tackle the issues posed by ArrayLists?

In the above code example Generic List class has been used to "contain" objects of type Person. At any time we can we can have the Generic List contain any other type, as below:-

//List of Ints
List myInts = new List();
myInts.Add(5);
myInts.Add(10);
myInts.Add(20);
foreach (int  x in myInts)
{
Console.WriteLine(x);
}
Console.ReadLine();
The above code snippet indicates that the same List class can be used to contain any datatype at any point of time, without requiring any kind of extra effort from the programmer's side.

The syntax for using any kind of Generic Class is as under :-

GenericClass objT = new GenericClass();

Where T is the datatype that' want to list, and GenericClass is the Generic Class which will wrap our desired datatype (that's the reason ,"contains" ,above has been marked in the double quotes and is marked bold :). This Generic Class can be our own custom Generic Class or the ones provided by the .Net Framework.

So technically, T gets replaced by the datatype at compile type. And that's the reaosn why a compile time error occurs when castinig is not done properly, it will be an InvalidCast Exception while using ArrayLists. Thus Generics enforce type checking at complie time only, making life less difficult.

Performance is another area where Generics make it sweet when compared to ArrayLists. Since T is "replaced" by our datatype at comile time only so, no time and resources are wasted in boxing and unboxing the objects.

Thus Generics are a very powerful and nice feature provided with .Net 2.0. Generics types are found sprinkled throughout the .Net2.0 BCLs; however System.Collections.Generics namespace is chock full of them.