Friday, July 17, 2009

Features in C# 3.0

Implicitly Typed Local Variables
C# 3.0 introduces a new keyword called "var". This new keyword enables you to declare a variable whose type is implicitly inferred from the expression used to initialize the variable. For example, consider the following line of code:
var i = 30;

The preceding line initializes the variable i to value 30 and gives it the type of integer. Note that "i" is strongly typed to an integer—it is not an object or a VB6 variant, nor does it carry the overhead of an object or a variant.
We can also write for strings like…
var s = "Hello again!";


In addition to implicitly declaring variables, you can also use the var keyword for declaring arrays as well. For example, consider the following lines of code:
int[] numbers = new int[] { 1, 2, 3, 4, 5};
string[] names = new string[] { "Dave", "Doug", "Jim" };

By using the var keyword, you can rewrite the preceding lines of code as follows:
var numbers = new[] { 1, 2, 3, 4, 5};
var names = new[] { "Dave", Doug, "Jim" };

The var keyword is NOT a completely new type, instead the compiler just takes a look at the right-hand side of the expression. If the right-hand side is an int, for example, the compiler will "replace" the var keyword with int.

Object initializers
Whenever you declare a class, most of the times the class is used only as a placeholder with getters and setters for holding property values without any additional logic. For example, consider a simple class like the following:
public class Person
{
int _id;
string _firstName;
string _lastName;

public int ID
{
get{return _id;}
set{_id = value;}
}
public string FirstName
{
get{return _firstName;}
set{_firstName = value;}
}
public string LastName
{
get{return _lastName;}
set{_lastName = value;}
}
public string FullName
{
get{return FirstName + " " + LastName;}
}
}


As you can see from the above class declaration, it doesn't contain any additional logic. The get and set properties are repetitive and they simply set or get the values of the properties without adding any value. In C#, you can simplify that by leveraging the new feature named Auto-Implemented properties. By taking advantage of this new feature, you can rewrite the above code as follows:
public class Person
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName
{
get
{
return FirstName + " " + LastName;
}
private set {;}
}
}

In the above code, when you declare a property, the compiler automatically creates a private, anonymous field that is available only to the property's get and set accessors. Note that the auto implemented properties must declare both a get and set accessor. However if you need to create a read-only property, modify the scope of the set accessor to be private.

Object and Collection Initializers
In previous versions of C#, you would create the object in one step and then populate its properties in a separate next step. However with C# 3.0, you can create the object as well as set its properties in a single line of code. For example, consider the following lines of code:
Person obj = new Person();
obj.ID = 1;
obj.FirstName = "Thiru";
obj.LastName = "Thangarathinam";
MessageBox.Show(obj.FullName);

In the above code, you create the Person object and set its properties appropriate values. By leveraging the object initializers feature, you can simplify the above code as follows:
Person obj = new Person { ID = 1, FirstName = "Thiru", LastName = "Thangarathinam" };
MessageBox.Show(obj.FullName);

In the above code lines of code, you directly assign the values to the properties of the Person object. Although you can simulate this behavior using constructor for the object, object initializers reduce the need to have a specific constructor for every variation of argument variation we need over time.
In C# 2.0, when you want to populate a collection, you need to write the following line of code:
List names = new List();
names.Add("David");
names.Add("Tim");
names.Add("Doug");

Now with the introduction of the new collection initializers feature in C# 3.0, you can shorten the above lines of code to a single line of code:
List names = new List {"David", "Tim", "Doug"};


Extension methods
Another cool thing is that you're able to add (static) methods to existing (default) classes. As an example, here is the code to add a ToMD5() method to the string class:

public static class StringExtensions
{
public static string ToMD5(this string s)
{
System.Security.Cryptography.MD5 md5;
md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(s));
// Return the result, replace unneeded "-"
return System.BitConverter.ToString(result).Replace("-", string.Empty);
}
}



Once compiled, all string objects now have the ToMD5 method. If you placed the extension class above in a seperate namespace, you should import this namespace to enable the usage. Example below:
string s = "Hello, this string is gonna be MD5-ed!";
Console.WriteLine(s.ToMD5()); // Prints the MD5 hash


As you can see from the preceding lines of code, the extension methods allow you to write cleaner and easy-to-maintain code.
Here are some of the key characteristics of extension methods:
• The extension method as well as the class that contains the extension method should be static.
• Although extension methods are static methods, they are invoked as if they are instance methods.
• The first parameter passed to the extension method specifies the type on which they operate and it is preceded by the "this" keyword.
• From within the extension method, you can't access the private variables of the type you are extending.
• Instance methods take precedence over extension methods in situations where they have same signature.


Anonymous Types
As the name suggests, anonymous types allow you to create a type on-the-fly at compile time. The newly created type has public properties and backing fields defined for the members you initialize during construction. For example, consider the following line of code:
var obj=new{ID=1,FirstName="Thiru",LastName="Thangarathinam"};

In the above line, you just specify the various attributes you want to have in the anonymous class and assign the instantiated object to a variable of type "var". The actual type assigned to obj is determined by the compiler. Since the compiler assigns the name of the type only at compile time, you can't pass an anonymous type to another method and it can only be used within the method they were declared.
When the compiler sees the above code, it automatically declares a class as follows:
class __Anonymous1
{
private int _id = 1;
private string _firstName = "Thiru";
private string _lastName = "Thangarathinam";

public int ID
{
get{return _id;}
set{_id = value;}
}
public string FirstName
{
get{return _firstName;}
set{_firstName = value;}
}
public string LastName
{
get{return _lastName;}
set{_lastName = value;}
}
}

Anonymous Types use the Object Initializer to specify what properties the new type will be declare.
Note that the anonymous types are just meant to be placeholders for quickly defining entity types and you can't add methods or customize the behavior of an anonymous type.

Lambda Expressions
Lambda expressions are simply functions and they are declared in the context of expressions than as a member of a class. It is an inline expression or a statement block which can be used to pass arguments to a method or assign value to delegate. All lambda expressions use the lambda operator => and the left side of the operator denotes the results and the right side contains the expression to be evaluated. For instance, consider the following lambda expression:
age => age + 1

The above function takes one argument named age, and returns age + 1 as the result. As you can see, Lambda expressions follow the below syntax:
(parameter-list) => expression;

where expression can be any C# expression or a block of code. Just like anonymous methods you can use a lambda expression in place of a delegate. Here are some sample lambda expressions and their corresponding delegates.
//Explicitly typed parameter
(Person obj) => MessageBox.Show(obj.FirstName.ToUpper());

//Implicitly typed parameter
(obj) => obj.FirstName == "Thiru";

//Explicitly typed parameter
(int a, int b) => a + b

//Implicitly typed parameter
(x, y) => { return x + y; }


As you see from the preceding lines of code, lambda expressions can be written in such a way that it can infer the parameter type from the signature of the delegate it is assigned to.

Query Expressions
This feature, also known as LINQ (Language Integrated Query), allows you to write SQL-like syntax in C#.
For instance, you may have a class that describes your data as follows:
public class CoOrdinate
{
public int x ;
public int y;
}

You now could easily declare the logical equivalent of a database table inside C# as follows:
// Use Object and collection initializers
List coords = ... ;

And now that you have your data as a collection that implements IEnumerable, you easily can query this data as follows:
var filteredCoords =
from c in coords
where x == 1
select (c.x, c.y)

In the SQL-like syntax above, "from", "where", and "select" are query expressions that take advantage of C# 3.0 features such as anonymous types, extension methods, implicit typed local variables, and so forth. This way, you can leverage SQL-like syntax and work with disconnected data easily.
Each query expression is actually translated into a C#-like invocation behind the scenes. For instance, the following:
where x == 1
Translates to this:
coords.where(c => c.x == 1)

As you can see, the above looks an awful lot like a lambda expression and extension method. C# 3.0 has many other query expressions and rules that surround them.

No comments:

Post a Comment