C# Type Inference


C# is a statically-typed language (type checking is performed by the compiler, as opposed to being performed at run-time),
which implies that variables must be associated with types at compile-time. Prior to version 3.0, you had to include the type
name in a variable declaration:

string name = "CoderSource.net";

In the context of generics, this requirement became tedious because you'd repeat type information:

List<string> planets = new List<string>();

C# 3.0 and successors take advantage of type inference to overcome this tedium. The idea behind this dynamically-typed
language-inspired feature is to introduce a variable without a type and let the compiler figure out the type on your behalf
via a type-inference algorithm. What this means to you, in the context of the previous examples, is that you can
alternatively specify the following shorter declarations:

var name = "CoderSource.net";
var planets = new List<string>();

Each variable declaration begins with keyword var. It continues with the variable's name and an initialization
expression. This expression is a requirement: failure to initialize a variable (as in var name;) results in a
compiler error. Also, assigning null to a variable results in another compiler error. Each error is generated
because there's no type information for the compiler to infer.

Behind the scenes, the compiler associates a type with the variable. You can determine this type by invoking the
GetType() method on the variable — each variable is actually an object, and this method is a member of each
object — to return the variable's System.Type instance, and then access this instance's Name
property to obtain the type name. Continuing from the previous examples:

Console.WriteLine ("name is of type "+name.GetType ().Name); // name is of type String
Console.WriteLine ("planets is of type "+planets.GetType ().Name); // planets is of type List`1

You can take advantage of type inference in any place where you declare a variable, including a foreach loop
header. For example, you can specify foreach (var planet in planets) instead of foreach (string planet in
planets)
to enumerate the planets list.

Type inference works with conditional expressions where the types of the expressions after the ? and
: agree. Consider the following example — age is of type Int32 and
isRetired is of type Boolean:

var age = 64;
var isRetired = (age < 65) ? false : true;

In contrast, var isRetired = (age < 65) ? false : "true"; will not compile because the expression after
? (false) is a Boolean, and the expression after : ("true") is a string.
What type would be assigned to isRetired?

Type inference also works with subtyping. Consider the following example, which introduces Base and
Derived classes, and assigns either a Base instance or a Derived instance to variable
x:

class Base
{
public virtual void Hello () { Console.WriteLine ("Base"); }
}

class Derived: Base
{
public override void Hello () { Console.WriteLine ("Derived"); }
}

for (var i = 0; i < 2; i++)
{
var usebase = (i == 0) ? false : true;
var x = (usebase) ? new Base () : new Derived ();
Console.WriteLine ("x is of type "+x.GetType ().Name);
x.Hello ();
}

The first time through the loop, x takes on type Derived (because usebase is assigned
false); it takes on type Base in the second loop iteration (where true is assigned to
usebase).

The previous examples are excerpts from TypeInferDemo.cs (located in this article's companion
code.zip archive), which is shown below, and which provides some additional examples of type inference.

// TypeInferDemo.cs

using System;
using System.Collections.Generic;

class TypeInferDemo
{
static void Main (string[] args)
{
var name = "CoderSource.net";
Console.WriteLine (name);
Console.WriteLine ("name is of type "+name.GetType ().Name);

var planets = new List<string>();
planets.Add ("Mercury");
planets.Add ("Venus");
planets.Add ("Earth");
planets.Add ("Mars");
planets.Add ("Jupiter");
planets.Add ("Saturn");
planets.Add ("Uranus");
planets.Add ("Neptune");

foreach (var planet in planets)
Console.WriteLine (planet);
Console.WriteLine ("planets is of type "+planets.GetType ().Name);

var age = 64;
var isRetired = (age < 65) ? false : true;
Console.WriteLine ("isRetired = "+isRetired);
Console.WriteLine ("age is of type "+age.GetType ().Name);
Console.WriteLine ("isRetired is of type "+isRetired.GetType ().Name);

// isRetired = "not retired";

for (var i = 0; i < 2; i++)
{
var usebase = (i == 0) ? false : true;
var x = (usebase) ? new Base () : new Derived ();
Console.WriteLine ("x is of type "+x.GetType ().Name);
x.Hello ();
}

var grades = new [] { 83, 96, 67, 72, 41 };
foreach (var grade in grades)
Console.WriteLine (grade);
Console.WriteLine ("grades is of type "+grades.GetType ().Name);

var circumference = System.Math.PI*20;
Console.WriteLine (circumference);
Console.WriteLine ("circumference is of type "+
circumference.GetType ().Name);
}
}

class Base
{
public virtual void Hello () { Console.WriteLine ("Base"); }
}

class Derived: Base
{
public override void Hello () { Console.WriteLine ("Derived"); }
}

The first of the additional examples shows type inference being used in an array context. As you can see, you don't need to
specify the array's type: it's inferred from the type of array elements. The second example shows type inference being used
in the context of a numeric expression.

Perhaps you're wondering why I commented out isRetired = "not retired";. Although it's legal to assign a value
of a different type to a previously-declared variable in a dynamically-typed language, it's not legal to do so in a
statically-typed language, such as C#.

Conclusion

C#'s support of type inference can make your code appear to be more dynamic, but it's still statically-typed. Perhaps of more
importance to you and anyone reading your source code, you'll save keystrokes as you enter the source code, and your code
will be somewhat easier to read. As an aside, it looks like type inference is finally coming to C#'s Java rival (in version
7).

Click Here to Download the attached sample