|

|
While attending TechEd 2007 in Orlando, FL I attended a great session on the new language features in C# 3.0. While I was in college (at Harvey Mudd College), I took a course on Programming Languages and study such languages as Scheme, Lisp, and Standard ML. It is great to see advancements in commercial programming languages that Academia has had for years. You can check out the official C# 3.0 at the MSDN Visual C# Developer Center. |
|
|
|
For all of the code snippets below I am using Visual Studio 2008. I started by creating a new C# Console Application and then I added a new class named Customers. Here is a recap of the new language enhancements:
1. Auto-Implemented Properties
It is always tedious to provide the getter and setters for properties. Visual Studio 2005 made life a bit easier with the Refactor -> Encapsulate Field feature, but it was still a lot of work to clean up the code to get everything organized nicely.
Auto-Implemented Properties allows you to define public data type and the compiler will take care of automatically generate a Public read/write property.
|
C# 2.0 |
C# 3.0 |
|
private int? _customerId = null;
public int? CustomerId
{
get { return _customerId; }
set { _customerId = value; }
} |
public int? CustomerId { get; set; } |
If you compare the IL that is generated using ildasm.exe, you can see how the property is managed
Standard Property (backed by a defined private data member)
Auto-Implemented Property
2. Object-Initializers
Often we need to set a bunch of properties once we new up an object from our class definition. In C# 3.0, we no longer have to use the object name dot notation to initialize the Properties. Instead we can use curly braces after the instantiation as shown below:
|
C# 2.0 |
C# 3.0 |
|
Customers c = new Customers();
c.CustomerId = 1;
c.Name = "Mike Hanley"; |
Customers c = new Customers()
{
CustomerId = 1,
Name = "Mike Hanley"
}; |
3. Collection-Initializers
As mentioned in the Object-Initializers enhancement above, the same is also true for Collections.
|
C# 2.0 |
C# 3.0 |
|
List<Customers> customers =
new List<Customers>();
customers.Add(c1);
customers.Add(c2);
customers.Add(c3); |
List<Customers> customers =
new List<Customers>()
{
c1, c2, c3
}; |
What is also nice is that Visual Studio 2008 provides full Intelli-Sense support as well.
4. local variable type reference (var)
The var keyword is one of the coolest new features in C# 3.0 and enables very elegant code. The compiler is able to determine the intended by evaluating the right hand side of the expression.
|
C# 2.0 |
C# 3.0 |
|
List<Customers> customers =
new List<Customers>(); |
var customers = new List<Customers>(); |
In the example above, the compile is able to determine that the customers data member is a List<T> where T is of type Customers. The scope of the var keyword is limited to a method. This ensures that the compiler can still ensure type safety. If it was allowed as a parameter in a method, there would be no way to determine what the type is at compile time.
5. Query Expressions (LINQ)
Query Expressions build upon the var keyword and Microsoft has provided a whole query framework named Language Integrated Query or LINQ. Query Expressions provide a convenient way to data projection and transformations in code.
|
C# 3.0 |
|
var query = from c in customers
where c.Name == "Mike Hanley"
select c; |
If you have ever used T-SQL, the syntax will look very familiar with one notable exception: the placement of the select clause. The from clause needs to be first in order to determine the type and to enable scenarios like Intelli-Sense support in Visual Studio 2008.
Let's consider the following code to print out a list of customers
|
C# 3.0 |
|
var c1 = new Customers() { CustomerId = 1, Name = "Mike Hanley" };
var c2 = new Customers() { CustomerId = 2, Name = "Kevin Hanley" };
var c3 = new Customers() { CustomerId = 3, Name = "Scott Stanfield" };
var customers = new List<Customers>() { c1, c2, c3 };
var query = from c in customers
where c.CustomerId > 0
select c;
foreach (Customers c in query)
{
Console.WriteLine(c.Name);
} |
The output of the code above will print out the names of the customers in the order in which they were added to the Customers list.
Now let's add an orderby clause to transform the data:
|
C# 3.0 |
|
var query = from c in customers
where c.CustomerId > 0
orderby c.Name.Split(' ')[0]
select c; |
Now the customers are sorted by first name:
6. Anonymous Types
It is possible to create a new instance of an object without specifying the class that should be used to create the type.
|
C# 3.0 |
|
// strongly typed Customer
Customer c1 = new Customer() { CustomerId = 1, Name = "Mike Hanley" };
var c2 = new Customer() { CustomerId = 2, Name = "Kevin Hanley" };
// anonymous type
var c3 = new { CustomerId = 1, Name = "Mike Hanley" }; |
7. Lamda Expressions
A Lamda Expression appears to be the evolution of the Anonymous Delegate feature that was implemented in C# 2.0. In C# 3.0, a Lamda Expression provides an easier way to write an anonymous method. A Lamda Expression has its roots deep in Programming Language theory—it appears very similar to the functor construct in Standard ML. It is essentially a way to store a function like a piece of data. Data members can then be applied to the Lamda Expression to produce a result. Lamda Expressions are strongly typed. They derive their type inference based on their usage.