Tuesday, September 15, 2009

C# 3.0 Implicitly typed local variable




In c# 3.0 we got a new keyword var which enable you to declare implicit local variables.
(i) Let’s look into the statement I made, its ‘local’ variable, that means cannot be used as class variables (instance variable) and is declared only in methods, not even as method parameter.
Figure1
Execution of Code1 breaks at:
Figure2
(ii)Next thing about ‘Implicit variable’ is, it should be initialized, why? It’s very obvious how the compiler will know to what type it should declare the variable as. If you correct the above two errors we will get our next error at line 19.
Figure3
(iii) Implicit variable cannot be null, rather cannot be null when you declare them.
Figure4
OUTPUT:
You can see strE.getType() returns ‘System.String[]’

(iv) When you declare an implicit variable with multiple types you will get a compile time error.
Figure5
Figure6


LINQ and Implicit variable
Declaring implicit variable using ‘Var’ keyword should be restricted is one of the recommendations in the c# specification. The reason could be that many of the new features of c# 3.0 have direct relation with LINQ and these new feature suits LINQ rather than normal programming. Let’s explore the implicit variable and LINQ relation.

A very good example and a simple one is given at http://msdn.microsoft.com/en-us/library/bb384061.aspx. It explains using a simple string. For you convenience I will put the example here (figure 7), now if you replace 2 instances of var with string[] and string respectively, since string look like a more likely type for ‘var’ here, you will be tempted to think replacing var with string makes things easier then, why ‘var’. However, doing so will result in following error.
ERROR :Cannot implicitly convert type 'System.Collections.Generic.IEnumerable' to 'string[]'

class ImplicitlyTypedLocals2
{
static void Main()
{
string[] words = { "aPPLE", "BlUeBeRrY", "cHeRry" };

// If a query produces a sequence of anonymous types,
// then use var in the foreach statement to access the properties.
var upperLowerWords =
from w in words
select new { Upper = w.ToUpper(), Lower = w.ToLower() };

// Execute the query
foreach (var ul in upperLowerWords)
{
Console.WriteLine("Uppercase: {0}, Lowercase: {1}", ul.Upper, ul.Lower);
}
}
}

/* Outputs:
Uppercase: APPLE, Lowercase: apple
Uppercase: BLUEBERRY, Lowercase: blueberry
Uppercase: CHERRY, Lowercase: cherry
*/
/td>
Figure 7
I know using string or build-in type is easy to relate, so let’s take a new example to understand the same scenario. Look at the code in figure8.Here instead of string we declare a class called SomeReturnClass and created a list< SomeReturnClass > with three values, to enable enumeration. Here use of ‘var’ cannot be replaced by SomeReturnClass for two reasons, SomeReturnClass does not have any constructor that take two int as parameters, the statement select new { x = w.updateValueI(), y = w.updateValueJ() }; therefore does not related to SomeReturnClass, therefore it’s more accurate to declare the output as ‘var’ and let compiler decide the type(Can call it anonymous type). Coming to the second use of ‘var’ at foreach (var v in objReturnClassX) , its very clear than objReturnClassX hold a type that better to be interpreted by compiler(anonymous type). Neither we have explicit convertion between ‘var’ and SomeReturnClass.
namespace CSharpFeatures
{

class ImplicitVariableLINQ
{
public static void GetImplicitVarLINQ()
{
List objReturnClassA = new List
{
new SomeReturnClass { i=0, j=2 },
new SomeReturnClass { i=2, j=2 },
new SomeReturnClass { i=2, j=0}
};
var objReturnClassX =
from w in objReturnClassA
select new { x = w.updateValueI(), y = w.updateValueJ() };

foreach (var v in objReturnClassX) {
Console.WriteLine("i:{0}, j:{1} ", v.x, v.y);
}
}
static void Main(string[] args)
{
ImplicitVariableLINQ.GetImplicitVarLINQ();
Console.ReadLine();
}
}

class SomeReturnClass
{
public int i, j;
public SomeReturnClass() { }

public int updateValueI() {
if (i <= 0) i = 100;
else i = i + j;
return i;
}
public int updateValueJ() {
if (j <= 0) j = 200;
else j = j + i;
return j;
}
}
}

Figure 8
OUTPUT