| |
| 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. |
|
| |
| |
| |