Published: 19 Jan 2007
By: Granville Barnett

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 generics, anonymous delegates, and others.

Generics held the limelight when .NET 2.0 was released, mainly because it was a feature that allowed a type, collection or 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 generics, 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!

When the 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

Unlike C# 2.0 which introduced features to bring itself up to date with other languages (generics were a supported feature in Java and 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 anonymous delegate).

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 C# 3.0.

Object Initialization

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 properties using 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 LINQ to SQL when we are interacting with entities on a frequent basis – that’s when you start to appreciate this feature.

Type Inference

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.

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

Anonymous Types

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

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 LINQ and LINQ to SQL.

Figure 7: Accessing the properties of an anonymous type

Lambda Expressions

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

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

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.

Extension Methods

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 (FirstName, LastName, and 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 class and method are 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, or 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 collections, SQL Server, XML, etc...).

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:

Expression Trees

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 expression tree

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

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

Continue reading and see our next or previous articles Next Article >>

About Granville Barnett

Sorry, no bio is available

This author has published 32 articles on DotNetSlackers. View other articles or the complete profile here.

Other articles in this category

C# 4.0 Reflection Programming - Part 2
As introduced in the first article, the most typically-used tools associated with .NET reflection ar...
C# 4.0 Reflection Programming - Part 3
In the previous article, we used the reflection to obtain the information of an assembly, module, ty...
C# 4.0 Reflection Programming - Part 4
In this last article of this series, we will learn what to do with reflection. But before making the...
Understanding and Using Extension Methods
Extension methods were new to C# 3.0. They allow you to add a method to an existing type without hav...
Introduction to C# 3.0 features
C# 3.0 introduced some of very useful features built on top of 2.0. This article explains the usage,...

You might also be interested in the following related blog posts

ASP.NET Core - An Introduction read more
An introduction to In-Memory OLTP Database Objects read more
Introduction to ASP.NET Identity (Video) read more
Introduction to ASP.NET Identity (Video) read more
Introduction to ASP.NET Identity (Video) read more
SQL SERVER What is Trace Flag An Introduction read more
An introduction to TypeScript read more
SQL SERVER Introduction to SQL Azure Database Throttling read more
Introduction to ASP.NET Core 1.0 video read more
Create a web site using AngularJS, MVC, web api - PART 1 : Introduction read more


Subject Author Date
placeholder Great beginning Gulab Chand Tejwani 11/19/2009 10:58 PM
Figure 9 Sean Fao 1/26/2007 6:22 PM
placeholder Nice Article with examples Anil Pandey 1/11/2010 1:00 AM
Figure 9 Fixed Sonu Kapoor 1/26/2007 6:56 PM
placeholder Excellent start Leon S 5/6/2007 6:20 PM
Excellent article, but a small error Samudra Sen 8/22/2008 12:09 PM

Please login to rate or to leave a comment.