Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

C# 3.0 Features

0.00/5 (No votes)
20 Dec 2007 1  
Shows the new language features for C# 3.0

Introduction

The C# language is getting more good looking than ever before. C# 3.0 is simply the definition of beauty. The new C# compiler is doing a lot of work for us so let us see how we can start using these beautiful features.

C# 3.0 Feature List

Let us start with a very handy feature, "Automatic Properties" (I am not sure what this is called, but this is how I like to call it :) ). Basically you can declare a property in C# without creating a data member explicitly, the compiler will go ahead and create it for us.

C# 2.0
private string prop;
public string Prop
{
get { return prop; }
set { prop = value; }
} 
C# 3.0
public string Prop { get; set; } 

As you can see, I am not declaring a member; all you have to do is specify what you want with the property (readonly or not).

Object Initializer

In C# 2.0, whenever you had to construct an object and set its initial state, we used to overload the constructor and pass the property values from the constructor. C# 3.0 introduces a new way of doing this via Object Initializers.

So if I had this class:

class MyClass
{
private string prop;
public string Prop
{
get { return prop; }
set { prop = value; }
}
} 
C# 2.0
MyClass c = new MyClass();
c.Prop = "asdads"; 
C# 3.0
MyClass c = new MyClass { Prop = "test" }; 

Collection Initializers

Collection Initializers are similar to Object Initializers, yet these allow you to add items inside your collection.

C# 2.0
List<string> list = new List<string>(2);
list.Add("test1");
list.Add("test2"); 
C# 3.0
List<string> list = new List<string>{"test1", "test2"}; 

Dictionary Initializers

As the name suggests, this is a new way by which you can add items in an IDictionary.

C# 2.0
IDictionary<string, string> dict = new Dictionary<string, string>(2);
dict.Add("test1", "test1");
dict.Add("test2", "test2"); 
C# 3.0
IDictionary<string, string> dict = new Dictionary<string, string> 
	{ { "key1", "value1" }, { "key2", "value2" } };

Extension Methods

This is quite a cool new feature. Basically you can attach methods at compile time to specific types. Let's say for example, you want to add a method to the string type. The string class is inside the System.dll and you do not have access to its source code. What you can do is declare an extension method for the specific type (you can also create an extension method for an interface and every class that implements that interface will have the method). An extension method must be declared as a static method and inside a static class. You have to pass "this" in front of the argument for the method (the type of the argument must be the type you want to extend). Let's try it out:

static class StringExtensions
{
public static string AppendMyNameToString(this string value)
{
return value + " Marlon";
}
} 

Now I can do the following code:

Console.WriteLine("Hello".AppendMyNameToString()); 

And the result will be:

"Hello Marlon" 

LINQ

I will not go into much detail on this topic because it's quite a large subject. If you are interested, visit this URL to get more information on LINQ. Basically LINQ is a declarative way  to query data. So instead of being imperative and using loops and if statements, you can tell C# what you want and LINQ will go ahead and build that data for you. Let's take for example, you have a list of strings and you want to get all strings that start with the letter "s".

string[] list = new string[] { "test", "marlon", "ema" }; 
C# 2.0
List<string> results = new List<string>();
foreach (string str in list)
if(str.StartsWith("t"))
results.Add(str); 
C# 3.0
IEnumerable<string> result = from x in list
where x.StartsWith("t")
select x; 

The above code is equivalent to this:

IEnumerable<string> result5 = list.Where(a => a.StartsWith("t")).Select(a => a);

The Where and Select methods are Extension Methods for the IEnumerable<T> interface that are declared in the Enumerable static class. The a => a.StartWith("t") syntax are lambda functions. We will explain this new feature next.

As you can see, LINQ is a declarative way by which you can query data. The code is more readable. Again I really want to stress this; I am not going into details of LINQ, yet this does not imply that LINQ is just this simple example, believe me, LINQ is HUGE. We will also do some more advanced queries later on in the article using orderby, group and joins. So hold on tight ... :)

Anonymous Types and Implicit Type Variables

Anonymous types are basically types that you do not declare as classes in your code. Basically when you create an anonymous type the compiler will create a class for you (with a very strange name :) ). So you might be saying but if I do not know the name of the type how can I reference it and create a variable of that type. The answer is the implicit type variable aka var. The var is a new keyword in C# that the compiler will change into the name of the type. So YES, you will not lose the static typing! You can also use the var in other scenarios to type in less characters when declaring a variable. The anonymous types are really handy when using LINQ queries to get a data structure out of the query as shown in the demo project (and even later on when discussing grouping in LINQ). So, let us create an anonymous type.

var x = new { Property1 = "hello", Property2 = 5 };
Console.WriteLine(x.Property1);
Console.WriteLine(x.Property2.ToString());

Now let's use the anonymous types in a LINQ query to see its potential:

var result3 = from q in testList
where q.TestProperty.StartsWith("T")
select new { Text = q.TestProperty, InnerDataList = q.ListOfData };


foreach (var item in result3)
Console.WriteLine("Text = {0}, Inner List Count = {1}", 
item.Text, item.InnerDataList.Count); 

Quite cool ee.. :)

Lambda Expressions

In C# 2.0, anonymous methods were given birth. This was quite a cool feature because you do not have to create a method in your class if you are going to use it just once for an event handler or something similar (like a Predicate<T> for instance). Besides, you can use any (there are some implications with this yet I will not talk about this today) variable in context of the anonymous method declaration.

C# 2.0
List<string> listOfstrings = new List<string>();
.....
listOfstrings.ForEach(delegate(string s) 
{ 
s.Trim(); 
}); 
C# 3.0
listOfstrings.ForEach(str => str.Trim());

As you can see in the above example, the lambda syntax is much cleaner. Basically with lambda, you can specify what parameters you want to pass by saying x=> now you can do anything with x since x is the parameter that is being passed to you. If you need to pass more than one variable to the lambda, you can do so by saying (x, y)=> and if you need to do more than one line of code in the body you can use the { } to do so.

Partial Methods

C# 3.0 introduces partial methods. Basically this is a way in which you can define a method in a partial class and implement it in another partial class. This feature is more for designers. For instance, the LINQ to SQL designer uses these features a lot.

partial class Customer
{
public partial void TestPartial();
}

partial class Customer
{
partial void TestPartial()
{
...
}
}

So I guess these are the new features (that I know of!!!) in C# 3.0. I did not go into much detail on each feature since every feature deserves a post on itself. Yet as promised I will go into some more LINQ. Again I will do only basic things and I will not go into much detail. I will only show how you can use these features.

Sorting with LINQ

You can sort a collection using LINQ very easily:

List<int> intList = new List<int>{15,22,1,14,25,96,3,8,91};
var sortQuery = from z in intList
orderby z ascending
select z; 

As you can see, the orderby keyword forces the collection to sort. (The sorting feature needs to be implemented by the LINQ provider. This sorting for LINQ to object is implemented for all collections).

Grouping in LINQ

Grouping is another cool feature in LINQ to Objects (I say LINQ to objects since there is more than one LINQ provider. There are LINQ to XML, LINQ to SQL and others... Yet I will only use LINQ to Objects in this post). For example, imagine that you have a list of numbers and you want to check which one has a remainder when divided by 2.

var groupQuery = from z in intList
group z by z % 2 == 0 into g
select new { Key = g.Key, Numbers = g };
foreach (var item in groupQuery)
Console.WriteLine("Reminder of 2: {0}, Count: {1}", item.Key, item.Numbers.Count());

As you can see, here I am using an anonymous type to create a group. The g.Key will be the different results of the group predicate (z % 2 == 0).

Joins in LINQ

Joins are very powerful for when you have relational data. For example, imagine that you have a list of customers and a list of orders for those customers. You want to find out the total bill for a customer by summing up all orders for the customer. You can do this very easily with LINQ.

Let us prepare some sample data:

Customer cust1 = new Customer { CustumerId = 1 };
Customer cust2 = new Customer { CustumerId = 2 };
List<Customer> customers = new List<Customer> { cust1, cust2 };
List<CustomerOrder> orders = new List<CustomerOrder>
{
new CustomerOrder { Customer = cust1, Total = 90 }, 
new CustomerOrder { Customer = cust1, Total = 190 }, 
new CustomerOrder { Customer = cust2, Total = 10 }
}; 

Now let us query this data to join the 2 lists by their relation.

var joinQuery = from cust in customers
join order in orders
on cust.CustumerId equals order.Customer.CustumerId
into customerOrders
select new { CustomerId = cust.CustumerId, Total = 
	customerOrders.Sum(custOrder => custOrder.Total) }; 

Let us print the result....

foreach (var item in joinQuery)
Console.WriteLine("Customer {0} has a total of {1}", item.CustomerId, item.Total);

Conclusion

C# 3.0 is really powerful and makes our life much easier (specially with LINQ). When you combine all these cool features together, you get quite a neat way to implement nice code that is readable and easy to understand. Again I want to point out that I did not go into much detail since the post would have been too large. Hope you enjoyed it...

History

  • 20th December, 2007: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here