Total votes: 3
Print: Print Article
Please login to rate or to leave a comment.
Published: 19 Jan 2007
In this article we will look at some of the language enhancements in C# 3.0. Throughout the article we will use code examples to demonstrate these new enhancements and how to apply them to real world problems. This article will give you the core understanding you will require to further explore the C# 3.0 language using many of its new features.
Where C# 2.0 left us
Back in 2005 we were all treated to the launch of the second major version of the .NET framework, the framework at the time introduced
anonymous delegates, and others.
Generics held the limelight when .NET 2.0 was released, mainly because it was a feature that allowed a
interface (amongst others) to have several faces – coupled with compiler type checking it was truly a major improvement to the .NET development world.
Another feature that also had its fair share of publicity was the introduction of
anonymous delegates. Unlike
anonymous delegates were welcomed with somewhat mixed opinions. On the face of it anonymous delegates encouraged the use of inline code which many did not like, coupled with their rather confusing syntax their functionality was somewhat of code obfuscation.
Anonymous delegates didn’t have the nice type signature normal methods had – and this scared people!
C# 3.0 specification got released in 2006 we all got a chance to see where the
C# language was heading. I dare say that we were all gleeful to see that the role of
generics was to be stepped up once more; however, something that was met with hesitance was the elevated role that
anonymous delegates would play in the language.
Where C# 3.0 picks up
C# 2.0 which introduced features to bring itself up to date with other languages (
generics were a supported feature in
C++ before they were in .NET),
C# 3.0 introduces radical features, many of which have never been seen in any other language before – this is where we, as .NET developers, are really getting excited. The future platform is not only one of evolution but also revolution!
As 2006 progressed and we got to May we all got to use the next features in
C# 3.0 courtesy of the May 2006 Language Integrated Query (
LINQ) CTP, for many of us who used that CTP we have never returned to
C# 2.0 – it is that good! Those who had doubts about the role
anonymous delegates would play were subdued by the clearer syntax of lambda expressions (an evolved
Even more recently (and what this articles’ code is based on) is the
Orcas January 2007 CTP. This latest CTP included newer
C# 3.0 bits, and a standalone
C# 3.0 compiler.
So with the scene set, we will work our way through the new features in
A new feature to
C# 3.0 is object initialization which allows a very convenient syntax for setting the values of
field variables. By default
C# 3.0 will allow you to use a
property like syntax to declare the values of any field variables with public visibility.
In fig. 1 we define a simple
Person type. We purposely define a parameter-less
constructor to emphasise the point of object initialization in
C# 3.0. Fig. 2 demonstrates how we would set these
C# 2.0, and fig. 3 shows the equivalent
C# 3.0 implementation.
Figure 1: Person type
Figure 2: Setting the values of properties in C# 2.0
Figure 3: Setting the values of properties in C# 3.0
From the examples you can see that
C# 3.0 provides a very convenient way to set the values of visible
properties/fields in any type, in fact this is very handy when using
SQL when we are interacting with entities on a frequent basis – that’s when you start to appreciate this feature.
My favourite feature by far is that of type inference using the brand new keyword
var. Before we get bogged down with what type inference means let us look at a simple example (Fig. 4).
Figure 4: Using type inference
In Fig. 4 the variable
granville is of type
Person, but how is this so? The type of the variable
granville is inferred from the type on the right hand side of the assignment (=) operator, so if you had an int on the right hand side of the assignment operator
granville would be an
int and would inherit all the behaviours of that value type and so on.
Orcas January CTP you would of had to run the application in debug mode to really prove type inference to yourself, however, in the
Orcas January CTP if you hover over
granville you will see a caption saying it is of type
Org.GBarnett.CSharp3.Person, and you can access its
member properties the usual way as shown in fig. 5.
Figure 5: Accessing properties of type inferred variable
I would argue though for clarity in your applications that using type inference for such scenarios in fig. 5 is not sensible, you should only use type inference when you are unsure of what type you are expecting to store in a variable.
We purposely covered type inference before that of
anonymous types, because type inference is the only way to store an
anonymous types’ associated information. In fig. 6 we replicate the
Person type by creating an
Figure 6: Replicating the Person type using an anonymous type
In fig. 6 we define a type with 3 properties, each of which are public be default so we can access them later on in our application and get/set their values (Fig. 7).
Anonymous types are used heavily in
Figure 7: Accessing the properties of an anonymous type
Lambdas provide a much clearer implementation of an
anonymous delegate; they provide the developer with the ability to define the type of any parameters and its return type upfront – unlike
In order to make
Lambda statements the saviours of
anonymous delegates let us look at the
anonymous delegate example in fig. 8 which takes a string parameter and returns a
Boolean value indicating whether or not the string parameter had a length greater than 4.
Figure 8: Creating a filter using an anonymous delegate
When looking at fig. 8 its syntax is somewhat odd and mysterious, its function is clear but the way it is expressed is not – enter
lambda expressions. Take a look at fig. 9 which is the same function but using a
Figure 9: Creating a filter using a lambda expression
One of the associations
lambda expressions bring with them is that of functional programming, this is mainly due to the expressive syntax which many can find confusing. In fig. 9 we define a
function filter which has one parameter x, and we express filter as returning
true only if the length of x, which is of type string has a length of more than 4.
Note: As this is only a skim through article on what is new on
C# 3.0 I encourage you to practice using
lambda expressions and becoming familiar with their syntax as this feature can hinder your progress with
C# 3.0 significantly.
In the past when we wanted to extend the functionality of a
type we had to derive from it directly and then override its methods accordingly, however,
C# 3.0 introduces
extension methods which allow you to extend the functionality of a type without touching that particular
type. We will take a simple example based on the
Person type we defined earlier in this article; we will create an
extension method to return a string of the details of that
person object (
Age). Take a look at fig. 10 for the
GetPersonInformation extension method listing.
Figure 10: Creating an extension method
There are a few things to note about fig. 10, the first is that the
static and the second is that we use this to refer to the current object calling the
extension method. Fig. 11 shows a code listing using the
extension method defined in fig. 10.
Figure 11: Calling an extension method
One of the most exciting new features on
C# 3.0 is the out of the box ability to query any collection that implements either
IEnumerable<T>. The premise behind Language Integrated Query (
LINQ) is to provide a standard set of operators which developers can use to query several data stores (in memory
We will query an in-memory
List collection of names and apply the
lambda expression we created earlier on, calling it using an
extension method called
Where(predicate), the code listing for this is displayed in fig. 12.
Figure 12: Querying an in-memory collection
For more on
LINQ please view my blog: http://gbarnett.org/archive/tags/LINQ/default.aspx
This particular feature of
C# 3.0 has been that hardest to grasp for many, it allows us to decompose a
lambda expression into its associated
expression tree. If you have ever done any compiler research then you may be familiar with the concept of an
expression tree. We will lead with an example shown in fig. 13 which is a simple
lambda expression which takes 2 integer parameters and returns the product of them.
Figure 13: Generating an
If we run fig. 13 you will see the body of the
lambda express (x * y) and its associated left and right children (x and y respectively). At this stage we can delve deeper and get very complex, which may very well be a good article for me to write in the future but for now the concept of an
expression tree should be familiar.
We need to cover one last thing about fig. 13 before we wrap things up and that is we can compile the
expression tree and then invoke its function. Fig. 14 shows the relevant code listing.
Figure 14: Compiling and invoking an expression tree
Over the course of this article I have exposed you to all the major new language enhancements in
C# 3.0; we have taken a look at some of the basic features like object initialization to some very advanced features like
About Granville Barnett
Granville Barnett’s interest in programming has spanned many languages – currently he is more than happy developing in C# (and the .NET framework in general), and C++. Granville also has an active interest in algorithm design and analysis. You can follow Granville’s exploration in programming via his blog http://gbarnett.org.
Sorry, no bio is available
This author has published 32 articles on DotNetSlackers. View other articles or the complete profile here.
Please login to rate or to leave a comment.