Tuesday, 9 April 2013

C#: object, var and dynamic

One of the interesting concept introduced in C# 4 was the “dynamic” keyword. Let’s see how it is different from the “var” or our old friend “object”.

1. System.Object has been with us since the birth of .NET framework. It is the base class of almost everything. It means we can write:

1:      object ostring = "Hello";
2:      object oint = 555;
3:      oint = "Hello int"; //point to a string
4:      ostring = -100;//point to an int

Usage: It is used when the type could be anything. For example a method using object parameter to accept any type and then casting it to appropriate type or use reflection to call operations; or a collection which can hold any type. However with the advent of generics ‘object’ is used less often when creating collections. The primary goal of object class is to be a base class and offer low-level services, which include methods which are common to almost every type in .NET framework or created by users. Methods like ToString(), Equals(), GetHashCode(), MemberwiseClone() are provided in the object class which can be reused or overridden (except Finalize of course which can’t be overridden).

2. “var” was introduced in C# 3.0 mainly to support anonymous types created using LINQ.

Taking this LINQ query:

1:  var courses = from course in Courses
2:                where course.Category.Contains("C#")
3:                select new {course.Title, course.Description, course.VideoLength};

The query will return a collection of type IEnumerable. What do you think will be the type of the items in the IEnumerable returned?

If we run this line:


courses.First().GetType().ToString();
//above line returns: <>f__AnonymousType0`3[System.String,System.String,System.String]

we get a type name which is generated dynamically!

But we may ask why not just use ‘object’ type to write it this way:

1:  IEnumerable<object> courses = from course in Courses
2:                where course.Category.Contains("C#")
3:                select new {course.Title, course.Description, course.VideoLength};
4:   
5:  foreach (var course in courses)
6:  {
7:      course.Dump();
8:  }

Yes it compiles without error but you will face a problem when you iterate the collection’s items. Let me attach a screen shot to show what I mean:

image

Since we specified <object> in the IEnumerable we get types as objects. But if we use var – it would implicitly create a new type and expose its properties to you. Again a screen shot with ‘var’

image

That’s the power of anonymous types, you don’t need to declare a new class with the three properties which you want from the collection. Let the compiler do everything for you!

Usage: ‘var’ cannot be used if they are not initialized and they cannot be used in method parameters.

   1:  void Main()
   2:  {
   3:      var i; //Error: Implictly-typed local variables must be initialized
   4:  }
   5:   
   6:  void Test(var i) //Error: The contextual keyword 'var' may only appear within a local variable declaration
   7:  {
   8:      
   9:  }

Also once the var is declared with a specific type it cannot be assigned a value which is not compatible. For e.g.

1:      var i = 123;
2:      i = false; //Error: Cannot implictly convert type'bool' to 'int'

3. “dynamic”: Dynamic was introduced in C# 4.0. It is very different from ‘var’ which is evaluated at compile time, where the dynamic variable is determined at run-time. Based on the value assigned to the dynamic variable the appropriate type is determined at run time (also known as late-binding).

1:      dynamic d = "Hello";
2:      string type = d.GetType().ToString(); //System.String
3:   
4:      d = false;
5:      type = d.GetType().ToString(); //System.Boolean

The above code compiles successfully. In fact even this will compile:

1:      dynamic dmic = 555;
2:      dmic.DoSomethingOnThisNumber();

But of course at run time it will identify it as System.Int and give error: “RuntimeBinderException: 'int' does not contain a definition for 'DoSomethingOnThisNumber'”Dynamic can also be used in un-initialized fields and method parameters. So both of uses below are legal:

1:  void Main()
2:  {
3:      dynamic i; //No Error
4:  }
5:   
6:  void Test(dynamic i) //No Error
7:  {
8:      
9:  }

No comments:

Post a Comment

Note: only a member of this blog may post a comment.