Home > C#, foreach > How var fixes a type hole in C#

How var fixes a type hole in C#

Assuming we have:

public class Base {}
public class Derived : Base {}
public class Unrelated {}

We can make a list of Base:

List baseList = new List<Base>();

And we can loop through the list:

foreach (Base item in baseList)

What other types can we use for the loop variable? We would expect to be able to use a type from which the collection’s item type is derived. In this case, that’s object:

foreach (object item in baseList)

And that’s fine, it makes perfect sense, because everything on our list is surely an object. If we had a list of Derived it would also make sense to let us use Base as the type of the loop variable. All good.

It wouldn’t make sense to let us use Unrelated:

foreach (Unrelated item in baseList)

It’s a certainty that the objects on our list are not of that type, so it has no hope of working. So we get a compiler error – good call!

But what about:

foreach (Derived item in baseList)

Now, the items on our list could be of that type – it’s certainly possible. But they could be of other types derived from Base. This is called a downcast, and if you need to do that, it’s often (but not always) a sign that there’s a kludge in your design.

What may be surprising (until you know the history of the way the language evolved) is that the compiler allows this to compile. In other words, it silently inserts a downcast. This is unfortunate, because it’s probably a mistake. Most situations where you required a downcast, you would do this instead:

foreach (Derived item in baseList.OfType<Derived>())

That way, anything that couldn’t be cast to the required type would be safely skipped over.

Fortunately, the var keyword comes to the rescue. Always use var to declare the loop variable and you won’t fall into this hole.

foreach (var item in baseList.OfType<Derived>())

The compiler uses the static type argument of the IEnumerable<T> interface, so in this case we get Derived items.

Note that var with a non-generic collection will be equivalent to object. But you can use the OfType trick again:

ArrayList whatever = new ArrayList();

foreach (var x in whatever.OfType<MyType>())

The foreach keyword predates generic collections, which is why it has the ability to silently cast; before generic collections, any code that looped through the contents of a collection would require a downcast, so it made a kind of sense to build it into the foreach keyword. Now we have generic collections, it makes almost no sense; but it’s not so bad because we have var to plug the hole, so we can’t fall into it.

Categories: C#, foreach Tags: , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: