Click Here to Install Silverlight*
IndiaChange|All Microsoft Sites
MSDN
|Developer Centers|Library|Downloads|How To Buy|Subscribers|My MSDN
 
CLR and Language Enhancements in .NET Framework 2.0 – Part 1
By : Saravana Kumar
 
Article Posted: October 07, 2004
 
The next release of .NET Framework 2.0 and Visual Studio .NET platform code-named Whidbey brings a series of new enhancements and altogether new advancements to all areas of .NET framework and visual studio. With its enhancements, it also paves the path to next generation Microsoft operating system "Longhorn". All this enhancements are designed to help developers both be productivity and take full advantage of the power of the .NET framework.
 
This two-part article series describes some of the Common Language Runtime (CLR) and language enhancements of .NET Framework 2.0. The description will follow WHY, WHAT and HOW theme. Why this new feature is required – value proposition, what it is – detail description and How to use it – examples. The new enhancements that are explored in this part 1 are,
 
1. Generics
2. Nullable Types
3. Iterators
4. Partial types
 
Note: The information in this article is based on a beta 1 version of .NET Framework 2.0, some of the features may change in the final release.
 
Generics
 
Generics is often called parameterized types that allows us to specify the type of data that a class can work with via parameters passed at declaration time. It permits classes, structures, interfaces, delegates, and methods to be parameterized by the types of data they store and manipulate.
 
Consider you need to create a class which stores collection of data and needs to provide a way to retrieve data from that collection. A class in .Net Framework 1.x will be like this,
 

public class Store
{
   object[] items;
   int current;
   public void add(object item)
   {
      // implementation for adding
   }
   public object this[int index]
   {
      // implementation for listing
   }
}

 
Items collection in this example is declared as an array of objects, so that you can store any type into this collection. Though object type comes with flexibility, it also has drawbacks. If you try to use this class, you will be able to store value of any type into this object.
 
Store intList = new Store();
intList.Add(1); // boxing
intList.Add(2); // boxing
intList.Add("AnyString"); // compile time error should come
int i = (int)intList[0]; // type casting is required
 
In the above example, compiler should give a compile time error when you try to add string data type into this object, but compiler won’t give any error since it is valid. If you try to store any value type (like integer) into this object, boxing will happen. Similarly if you want to retrieve any value from this object, you need to cast it to corresponding type. Though you have the flexibility of storing any type into this collection, you don’t have type safety and there is a performance hit due to boxing and downcasting.
 
Instead of this way, if you have an option to pass data type which this class is going to work on as parameter. For example,
 
public class Store<T>
{
     T[] items;
     int current;
     public void add(T item)
     {
       //your implementation goes here
     }
     public T this[int index]
     {
      //your implementation goes here
     }
}
 
In this class, you are getting T as type parameter. The type parameter T acts as a placeholder in this class until an actual type is specified at declaration. So when you use this class, you will be passing actual type for T as type argument. For example,
 
Store<Int32> intList = new Store<Int32>();
intList.Add(1); // No boxing
intList.Add(2); // No boxing
intList.Add("AnyString"); // Compile time error
int i = intList[0]; // No Type casting
 
We are passing Int32 as type argument. So every occurrence of T in Store class will be replaced with type argument (Int32). So when the Store class with type argument Int32 is instantiated, items collection is array of Int32 instead of object as in our previous example. Because of this, if you try to add any other type other than Int32, a compile time error will occur. Similarly there is no boxing when you try to add Int32, since there is no need for conversion of value type to reference type as it is stored as Int32 only. This also avoids the explicit casting to actual type when the value is fetched from this collection. In .Net Framework 2.0, generics allows us to create class of this nature.
 
Generics allow you to provide better compile-time validation, improve performance and type safety when defining and using the types required to handle multiple types. Generics is supported in C# as well as VB.NET.
 
In .NET Framework 2.0, generics is build into the CLR itself. Hence they have built in support for Intermediate Language (IL). When you compile generic type, it will be compiled into IL like normal type. But generic type IL will have information about type parameters as metadata. Compiler will use generic metadata to support type safety during compilation of type which uses generic type. The first time an application creates an instance of a constructed generic type, such as Stack<int>, the just-in-time (JIT) compiler of the CLR converts the generic IL and metadata to native code, substituting actual types for type parameters. Subsequent reference to that generic type with same type argument will use the same native code. This behavior is different between value type and reference type. One type is created for each unique value-type type argument. That type is then reused for all other constructed types having the same type parameter. This improves performance by not requiring any type casting. One type is created for all reference-type type arguments, using object references as the type parameter. That type is reused for all other constructed types that are reference types. This reduces code bloat in memory.
 
To know more about generics, refer this article on Generics
 
New .NET Framework Collections
 
Microsoft is releasing a new set of collection classes equivalent to existing collections but rewritten to use generics. For example Arraylist is rewritten to List<T>. All this collections are placed under System.collections.generic namespace. A test is done to find out the performance difference in using Arraylist and List<T> collection. In this test 30,00,000 items of various data types has been added to both the collections and all the items are retrieved back from the collections. This test basically finds out the performance improvement by using generics. Performance results are mentioned in milliseconds. The performance difference is very high for both value type and reference type.
 
Collection Name Integer String Date Time Custom Object
  Add Fetch Add Fetch Add Fetch Add Fetch
Arraylist 3860 3508 1482 786 5769 4848 1916 1778
List<T> 511 1474 1477 132 1158 4166 1328 722
 
Performance Results of Generics
 
Nullable Types
 
One of the main difference between value type and reference type variable is that reference type supports null. You can store null in reference type, but value type will always have some value. Though you assign null value to a value type, automatically it will take default value instead of null. For example zero is default value of integer.
 
In many scenarios you will require to store null in value type. For example, if you are having a value type variable “bonus” in a person class to store bonus amount. You can’t differentiate between person with zero bonus with the person for whom bonus process in not instantiated. Since for both the person, bonus variable will have value zero only. In this type of scenario, it will be better if value type supports null.
 
In .Net Framework 2.0, Microsoft is providing a generic type (Nullable<T>) using which you can store null in value type. This Nullable type is implemented as generic structure with two read only properties,
 
HasValue Property: It is a Boolean type property, using this property you can find out whether that object has value or not. If it is false, then the value of that object is null. If you try to access “Value” property when HasValue is false, it will throw an exception.
Value Property: Type of this property is same as underlying type of Nullable type. This property is used to access the value of Nullable type when HasValue is true.
 
Example for using Nullable type
 
Nullable<Int32> a;
Nullable<Int32> b;
a = 1;
b = null;
if (a.HasValue )
{
      MessageBox.Show(a.Value.ToString()) ;
}
Else
{
      MessageBox.Show("It has null value");
}

In C#, you can declare Nullable type like this also
int? a; // equivalent to Nullable<int> a;
 
Iterators
 
In .NET Framework 1.x, if you want your collection object to be enumerated. If you want to use your collection object in foreach statement. Then you need to implement IEnumerable interface and you need to expose GetEnumerator method in your object. But implementing GetEnumerator method involves quite a lot of work. You need to take care of looping through your collection and state management to keep track of the current position in your collection. For example, if you want to implement GetEnumerator method in the Store class,
 
public class Store
{

// Other method implementation goes here
public ListEnumerator GetEnumerator()
{
return new ListEnumerator(this);
}

}

public class ListEnumerator : IEnumerator
{
Store store;
int index;

internal ListEnumerator(Store store)
{
this.store = store;
index = -1;
}

public bool MoveNext()
{
int i = index + 1;
if (i >= store.count()) return false;
index = i;
return true;
}

public object Current
{
get { return store[index]; }
}

public void Reset()
{
//implemetation goes here..
}
}

 
Basically you need to maintain state of the collection while looping through collection. For this simple collection itself, we need to write this many lines of code. But in .NET Framework 2.0, Iterators helps you to create an enumerable collection with just few lines of code. New keywords yield return and yield break is introduced in .NET Framework 2.0.
 
The yield return statement produces the next value of the iteration.
The yield break statement indicates that the iteration is complete.
 
Using this keyword, you can write getEnumerator method very easily. For example,
 

public class Store
{

     // Other method implementation goes here

     public IEnumerator GetEnumerator()
     {
        for (int i = 0; i < count; i++)
        {
           yield return items[i];
        }
     }
}

 
You need to just loop through your collection and return the items using yield return statement. Internally C# compiler will take care of maintaining state of your collection when this collection is used in for each statement. Compiler generated code for Store class using iterators is shown below,
 
 
If you see this Store class, a new complier generated class <GetEnumertor>d__0 is added to this class and reference to this class is added in GetEnumerator method. This class is similar to the class ListEnumerator class that we created if we want to implement enumerator in .NET Framework 1.x. But in .NET Framework 2.0, it is done by complier. We just need to use new yield statement. This feature is only available in C# and not in VB.NET in this release.
 
Partial Types
 
In .NET Framework 2.0, you can split your class source code into many files and when you are compiling you can compile all the files together. This is possible by using new keyword partial, you just need to mention that class is partial using this keyword “partial” when you are defining that class in each source file. But when you are compiling that class, all your partial class should be placed together in a project. After you compile that project, you can’t add any partial class afterwards to that executable. Again you need to compile all the class together with the new class added. For example,
 

public partial class MyPartialClass
{
  public void Method1()
  {
   // Implementation
  }

}

public partial class MyPartialClass
{
   public void Method2()
   {
    // Implementation
   }
}

 
You can declare these classes in two different source file. But when it is compiled together, it will be merged into one class. Compiled code of that class will look like this,
 

public class MyPartialClass
{
  public void Method1()
  {
   // Implementation
  }

  public void Method2()
  {
    // Implementation
  }
}

 
This feature is extensively used when the same class is developed by multiple developers at the same time. Each developer can develop the same class at the same time in different source files with the help of partial class, but all the source files should be compiled together. This feature is also extensively used in ASP.NET and Windows Forms to separate GUI elements declaration and IDE generated code from user code. This feature is available both in VB.NET and C#.
 
Conclusion
 
In this article we have explored Generics, Iterators and Partial Types. In the next part of this article, we will explore other CLR and Language Enhancements like
 
1. Anonymous methods
2. Static Classes
3. Namespace Qualifier and External Assembly qualifier
4. Security enhancements and BCL Enhancements.
 
 
 

©2009 Microsoft Corporation. All rights reserved. Contact Us |Terms of Use |Trademarks |Privacy Statement
Microsoft