New Features in C# 2008


Several language extensions are introduced in C# 3.0 code-named "Orcas". These extensions are built on C# 2.0 to support functional programming style.

  • Auto-implemented Properties

  • Implicitly Typed Local Variables

  • Extension Methods

  •  Lambda Expressions

  • Object Initializers

  • Collection Initializers

  •  Anonymous Types

  • Partial Methods

  • Expression Trees

  • Query Expressions

Before jumping into the new features I would like to introduce the readers to the new world of functional programming in.Net. Programming styles are generally classified into two kinds.
 

  1. Functional Programming
  2. Procedural Programming

 Functional programming otherwise called as declarative programming was designed specifically to support pure functional approach in problem solving. In contrast, most of the OO Programming languages like Java, C#, C++ etc., primarily support Procedural programming.

 

Primarily Procedural languages deal with algorithms on how the tasks are performed in problem solving. Whereas, in the Functional programming programmers define methods or functions and focus mainly on how the information is transformed.

 

Below sections I would be covering the major language enhancements brought in to C# 2008.

 

Auto-Implemented Properties

 

In C# 2005 defining the properties (accessors or mutators) require large typing effort even though it is used for a very simple task of encapsulation of data.

 

In C# 2.0 properties are declared as follows.
 

        private int iEmpId;

        private string strEmpName;

 

        public int EmpId

        {

            get { return iEmpId; }

            set { iEmpId = value; }

        }

 

Samething is redfined in C#3.0 using auto-implemented properties feature as follows.
 

public class AutoProperties

{

       public int EmpID { get; set; }

       public string EmpName { get; set; }

       public int Age { get; private set; } // read-only

 

}

 

Behind the scene, compiler automatically creates private, anonymous fields that can be accessed from the above auto-implemented properties.

 

Implicitly typed local Variables
 

When a Local variable specifies var as the type, then the type of the variable will be inferred automatically by the compiler from the expression. For example:

 

var iAge = 33;

var strName = "Chandra";

var Expr = 5.0 * 6.0;


All the above mentioned local variables are strongly typed at the compile time and are valid Expressions. They are equivalent to
 

int iAge = 33;

string strName = "Chandra";

double Expr = 5.0 * 6.0;

 

These implicit variables come with some restrictions and they are discussed below
 

  • Implicit Variables are not allowed in the global scope.
  • Variables that has the value of null reference cannot be declared as type 'var'. Compile-time type cannot be null.

var x = null;
 

  • Declaration must include initialization expression also.

var y;

 

  • Initialization can include an object or collection initializer with the keyword "new".

Ex., var c = new Int32[] { 1, 2, 3 };

 

Following Statements will fail as there they are not "new" Expressions.

 

var z = { 1, 2, 3 };                      

var obj = Emp{ EmpID = int.Parse("1234"), EmpName = "Chandra" };

 

  • Cannot have auto poperties declared as var.

public var EmpID { get; set; }

 

  • Implicit variables can also be used in the iterative statements like "for" statement and resource-acquisition statements like "using" statement.

      foreach (var a in new Int32[] { 1, 2, 3 })

Console.WriteLine(a);

 

Keyword 'var' was not part of default list. So for the backward compatibility if a member of type named 'var' exists in the scope, the declaration will refer to that type only. A general warning would be generated by the compiler to bring attention of the programmer.

 

Methods cannot return implicit types. Following code will result in compile time error.

 

public var BadThings()

{

    return 0;

}

 

Extension Methods

 

They are static methods that can be invoked like an instance method. Static methods can be declared only in Static classes. Let's see how static methods are declared.

 

        public static void ExportToExcel(this DataSet ds)

        {

            //do something...

        }

 

Extension methods are declared by specifying the "this" keyword as the modifier in the first parameter.  The ExportToExcel method is declared as an extension method for the DataSet class.

 

Extension methods are invoked as soon the namespace of the containing static class is included.

 

In the below code snippet, the extension method is declared inside
 

namespace Orcas.Samples

{

public static class Extensions

{

    public static void ExportToExcel(this DataSet ds)

    {

        //do something...

    }

}

}

 

Above method is invoked in the client program as,
 

using Orcas.Samples;

 

DataSet ds = new DataSet();

ds.ExportToExcel();

 

Rules governing Extension methods are
 

  • Instance methods should be declared only in the static classes.
  • Instance methods take precedence over extension methods
  • Extension methods imported in inner namespace declarations take precedence over extension methods imported in outer namespace declaration

Object Initializers
 

Fields or properties of an object can be initialized and values can be assigned at the creation time with out calling the constructor to initialize these members.

 

Let's learn this from the below example.

 

internal class Employee

{

        private int iEmpID;

        private string strEmpName;

 

        public int EmpID

        {

            get { return iEmpID; }

            set { iEmpID = value; }

        }

        public string EmpName

        {

            get { return strEmpName; }

            set { strEmpName = value; }

        }

        public Department Dept {get;set;}

 

  }

 

We have defined an Employee class with few attributes. Let's now create an object for this class and initialize the Employee object.

 

var Emp = new Employee{EmpID = int.Parse("1234"), EmpName = "Chandra"};

                                   

Above code snippet creates a new Employee object by assigning values to the properties.

 

This code results in same output as follows
 

Employee Emp = new Employee();

Emp.EmpID = int.Parse("1234");

Emp.EmpName = "Chandra";

 

Collection Initializers
 

Just like Object Initializers collections can be initialized easily using Collection Initializers. In the below example, a new Integer array is constructed and initialized with some element values.
 

var c = new Int32[] { 1, 2, 3 };

 

Same construct can be used to initialize custom object (List<T>) collections also.

 

internal class Address

    {

        public string StreetName { get; set; }

        public string City { get; set; }

        public string Country { get; set; }

    }

 

A new Address class is defined to hold Street name, City and Country. We are going to initialize objects of Address class using collection initializers. Here object initializers are separated by commas with in the braces of collection initializers.

 

var lstAddress = new List<Address>

{

    new Address{StreetName = "Mount Road", City = "Chennai", Country="India"},

    new Address{StreetName = "M.G.Road", City = "Bangalore", Country="India"}

};

 

Anonymous Types

 

Without explicitly defining a type, we can define types that have encapsulated read-only properties. These types are anonymous and compiler generates the type name as required. These types were not defined by the programmers at the design time and are not available at the source code level. These anonymous types are nothing other than unnamed structure types. These types can be accessed by using var keyword.

 

var objEmployee = new

{

EmpID = 3235,

EmpName = "Chandra"

};

 

IDE provides intellisense at the design time itself.

Intellisense.jpg
Lambda Expressions
 

It's nothing but Anonymous Methods that contain expressions and statements. It is a replacement to C# 2.0 Delegates. Lambda expressions are more of a functional syntax.

 

Let's look at an example how delegates are defined in the earlier releases of C#. This way you should be able to understand and appreciate the functional syntax.

 

C# 1.0 Syntax:
 

        delegate int Sum(int i, int j);

 

        public void Learn()

        {

            Sum objSum = new Sum(Add);

            Console.WriteLine(objSum(5, 5));

        }

 

        private static int Add(int i, int j)

        {

            return i + j;

        }

 

C# 2.0 using Anonymous methods:
 

        delegate int Sum(int i, int j);

 

        public void Learn()

        {

            Sum objSum = delegate(int i, int j) {return i + j;};

            Console.WriteLine(objSum(5, 5));

        }

 

C# 3.0 using Lambda Expressions:
 

        delegate int Sum(int i, int j);

 

        public void Learn()

        {

            Sum objSum = (int i, int j) => i + j;

            Console.WriteLine(objSum(5, 5));

        }

 

Let's learn how to create Lambda expressions. Lambda operator => is used to define these expressions. It is read as "goes to".

 

E.x.

i => i * 2

 

Input parameters to the expressions are defined before the Lambda operator =>. Expressions are defined on the right-hand side part of the Lambda operator.

                           

We can also define Lambda statements by defining more than one statement encapsulated inside { }. return statement should be part of the statement Lambdas.
 

delegate int Sum(int i, int j);

 

        public void Learn()

        {

            Sum objSum = (int i, int j) => { return i + j; };

            Console.WriteLine(objSum(5, 5));

        }

 

 

Standard Delegates

 

C# 3.0 comes with few standard delegates. This helps programmers to create a delegate up to 4 parameters without creating their own. Below is the method reference.

 

public delegate TResult Func<TResult>(); // with no parameters

public delegate TResult Func<T, TResult>(T arg); // with One parameters

public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2); // with 2 Parameters

public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);

public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);

 

A simple example is given below:
 

// using Func delegates adding 2 string and returning string...

Func<string, string, string> cdL3 = (one, two) => { return one + two; };

 

var result = cdL3("Chandra", "mouli");

 

Conclusion
 

I will talk more about Expression trees and LINQ in my next article. Happy programming till then!!!


Similar Articles