Loading... Loading latest track...

Understanding the C# var keyword

In recent weeks I have been helping my boss to recruit for new C# developers by sitting in and asking the candidates some technical questions. One of my questions was:

Can you explain to me the C# 'var' keyword?

The var keyword was introduced in C# 3.0 several years ago, so this question wasn't considered to be a modern or difficult question (such as asking for an explanation of the more recent dynamic type) - but I was surprised how many developers didn't get it right. Plus, while browsing a MonoTouch article recently, I felt compelled to reply to an ill-informed comment where someone said "var is overused. You should strongly type your variables instead." This, along with an answer a candidate gave me in a recent interview when he said "isn't the var keyword slower?" prompts me to write this post.

I would sum it up as follows: the var keyword is a shorthand way of allowing the compiler to infer the type for you - to save your fingers some work.

Some things need to be made quite clear:

  • Using var doesn't make your variables "weakly typed". All variables declared as var are strongly typed! (C# is a statically typed language - everything is strongly typed!)
  • var isn't a type. The actual type is figured out at compile-time.
  • Due to the fact that the actual types are resolved at compile-time, the var keyword cannot be "slower".
  • It sometimes increases code readability.
  • It sometimes decreases code readability.
  • It is sometimes optional, but sometimes required.

The var keyword is not a type. System.String is a type. Int32, decimal and object are types, but var is not a type. The actual type is resolved at compile-time: it is inferred based on the right-hand-side of the equals sign. Here, the variable i is strongly typed as an integer:

var i = 3;

It is identical to typing this:

int i = 3;

In both of those examples the variable i is strongly typed as an integer. Due to that fact, this will not compile:

var i = 3;
i = "foobar";

That's right, it's not a bug, it's not "sloppy coding", or an explosion at runtime: it's a compilation error. Due to the fact that the keyword var is inferred at compile-time, this statement will not compile either:

var i;

Nor will this:

var i = null;

The last one couldn't possibly compile: what if I wanted i to be an integer, then assigning null to it doesn't make sense, it would be equivalent to this statement (which also does not compile):

int i = null;

I mentioned that there are times when the var keyword can increase code readability, but also decrease it. I think there is no need for it on the first line of code in the sample below, compared with the equivalent second line:

var i = 3;
int i = 3;

My variable i is an integer, but I haven't saved myself any keyboard strokes or saved the reader some time: I think I have slightly decreased the code readability by using var. But in the example below I think that I have increased code readability on the first line, in comparison to the equivalent second line:

var config = new List<KeyValuePair<string, string>>();
List<KeyValuePair<string, string>> config = new List<KeyValuePair<string, string>>();

In the previous two examples the use of the var keyword is optional. Whether using it results in more or less readable code is a choice that the programmer must make. Using the var keyword in the example below is not optional, it is required:

var query = customers.Select( c => new { Name = c.Name } );

That was a LINQ lambda expression returning an anonymous type. The same can be expressed using LINQ's comprehension syntax:

var query = from c in customers
select new
{
Name = c.Name
};

In both of those examples, an anonymous type is being returned from the LINQ expression. Don't be fooled though: even an anonymous type is strongly typed. It is another kind of "shorthand" - instead of saying (as with the var keyword) I know the type, but I'm too lazy to write it out, with anonymous types you are saying "I know the type, but I'm too lazy to create the type myself - so I'll let the compiler do it". Due to the fact that the compiler will create the type for us, we have no option but to use the var keyword to create the type.

With a new version of C# looming - developers risk falling behind the pack if they aren't even up to speed with the current version of C#.

In my last post I found out that you can bind anonymous types to repeaters in C#, but there's a lot of other interesting things you can do with anonymous types, such as performing a LINQ Union operation on two anonymous type collections. I'll show how this is possible using a simple example.

Firstly, let's say that you have created a web application where people can use their existing facebook or twitter account to log on to your website. In a slightly naive example we will first get a list of users from facebook, and another list from twitter, and join them together into one user list and then work with them.

XDocument facebookXml = GetFacebookUsers();

var facebookQuery = from user in facebookXml.Descendants("FacebookUser")
select new
{
Username = (string) user.Element("Username"),
Firstname = (string) user.Element("Firstname"),
Lastname = (string) user.Element("Lastname"),
Birthday = (DateTime) user.Element("Birthday"),
Country = (string) user.Element("CountryName")
};

XDocument twitterXml = GetTwitterUsers();

var twitterQuery = from user in twitterXml.Descendants("TwitterUser")
select new
{
Username = (string) user.Element("Username"),
Firstname = (string) user.Element("Firstname"),
Lastname = (string) user.Element("Lastname"),
Birthday = (DateTime) user.Element("DOB"),
Country = (string) user.Element("Country")
};

On a side note, I'm casting the inner XElement objects to string, or DateTime; I prefer doing this to user.Element("Username").Value due to the fact that the end result is the same but we avoid the NullReferenceException that .Value may give us.

Although the two XML document's come from different sources and in fact have different structures and element names, the key thing here is that the anonymous type I have created in the facebookQuery has the same property names (and types) as the anonymous type I create in the second query (the twitterQuery). The .NET compiler is clever enough to realise that these two anonymous types are not two distinct anonymous types with the same properties, but are in fact the same anonymous type. The LINQ union set operator can obviously only be used on sets/collections of the same type, but that is exactly what we want to do next (the only difference being that we are allowing the compiler to create the type for us). Here is what we would want to do next:

var allUsers = facebookQuery.Union(twitterQuery);

Or most likely a more useful query like the one below:

var allUsers = facebookQuery.Union(twitterQuery)
.Distinct()
.Where(u => u.Country == "Norway");

One thing to note is if we add another property to the first anonymous type, for example a new string property called MobileNumber, the anonymous types will now be different (i.e. they will be two distinct anonymous types) and we will not be able to use the LINQ Union operation any longer:

var facebookQuery = from user in facebookXml.Descendants("FacebookUser")
select new
{
Username = (string) user.Element("Username"),
Firstname = (string) user.Element("Firstname"),
Lastname = (string) user.Element("Lastname"),
Birthday = (DateTime) user.Element("Birthday"),
Country = (string) user.Element("CountryName"),
MobileNumber = (string) user.Element("Mobile")
};

var twitterQuery = from user in twitterXml.Descendants("TwitterUser")
select new
{
Username = (string) user.Element("Username"),
Firstname = (string) user.Element("Firstname"),
Lastname = (string) user.Element("Lastname"),
Birthday = (DateTime) user.Element("DOB"),
Country = (string) user.Element("Country")
};

// This will result in a compile time error
var allUsers = facebookQuery.Union(twitterQuery);

DataBinding with Anonymous Types in C#

I wanted to use an ASP.NET repeater to bind some data to a web form, but the data in the code came from two different places. I used LINQ to join my two data collections together, but the problem was that this resulted in my query returning an IEnumerable of anonymous types. I thought that this would mean I'm not going to be able to bind these anonymous type objects to my repeater without creating a strongly typed class or struct.

It turns out that I was wrong: I can bind anonymous types to a repeater! That's pretty cool, and I'll show you how I did it. My LINQ query looked like this:

Customer[] customers = GetCustomers();
Country[] countries = GetCountries();

var query = from customer in customers
            join country in countries on customer.CountryID equals country.CountryID
            where customer.Age > 21 &&
                  country.Name == "United Kingdom"
            select new
                       {
                           CustomerName = customer.Name,
                           CountryName = country.Name
                       };

MyRepeater.DataSource = query.ToArray();
MyRepeater.DataBind();

As you can see, I'm using CustomerName from one type of object, and CountryName from another type, and joining these together into a new anonymous type.

After this, in my HTML/ASCX I can use a repeater like this:

<asp:Repeater ID="MyRepeater" runat="server">
    <ItemTemplate>
        <p>
            <%# Eval("CustomerName") %>
            lives in
            <%# Eval("CountryName") %>
        </p>
    </ItemTemplate>
</asp:Repeater>

When you think about it, this actually makes sense. Anonymous types of course are real types - it's just that the compiler generates the type for me, so I don't have to.