LINQ: What is the purpose of var?
Larsenal, a C9’er posted a comment on the C9 forums about the Introducing LINQ video and asked a really good question so I thought I should repost my response here.
Larsenal's Question
“ I've watched this video on LINQ in C#. If the type is set at compile time, what's the benefit of using the "var" keyword? It seems like it just makes the code less readable.
I look at the first example here, and wonder why not just replace the var with string[]?”
My (slightly modified) Answer
If you’ve never heard of var, var is a new way to declare variables in C# 3.0 that uses implicit typing. Let’s show a quick couple of examples.
Before 3.0
string myString = “hello”;
int myInt = 5;
float myFloat = 5.5f;
After 3.0
var myString = “hello”;
var myInt = 5;
var myFloat = 5.5f;
The distinction here is that var is not the same as object, or the JavaScript “var” data type as it’s actually strongly typed, but inferred from whatever the value is being assigned.
Create your own types with var
The big reason for var in my opinion is that LINQ enables you to create or "project" wholly new data types without having to create the type themselves. This is known as projection.
Let's look at a sample query that I blogged about earlier:
string[] aBunchOfWords = {"One","Two", "Hello", "World", "Four", "Five"};
var result =
from s in aBunchOfWords
where s.Length == 5
select s;
In this example, I am projecting the string "s", so I could have easily replaced var with the type IEnumerable<string> as shown in bold below and my code would have worked fine.
IEnumerable <string> result =
from s in aBunchOfWords
where s.Length == 5
select s;
But what if I wanted to project something more complex, like a type that contains
1) the string
2) the length of the string as an integer
3) the first three characters of the substring
Using the power of var, this is pretty easy as shown in bold below:
var result =
from s in aBunchOfWords
where s.Length == 5
//Creates a new anonymous type with name/value pairs
select new {Value=s, Length=s.Length, FirstThreeLetters=s.Substring(0,3)} ;
//Print values
foreach (var x in result)
Console.WriteLine("Value: {0}, Length:{1}, SubString:{2}",
x.Value, x.Length, x.FirstThreeLetters);
This prints:
Value: Hello, Length:5, SubString:Hel
Value: World, Length:5, SubString:Wor
As you can see, I can use "select new" and project my own custom type with field name/value pairs. Under the covers var infers the field names, field values, and field data types and creates an anonymous type with the three fields I projected.
Without var, you would have to create the anonymous type yourself, which basically means you have to create a custom class for the projected type as shown below:
public class MyType {
public string Value;
public int Length;
public string FirstThreeLetters;
}
The subsequent code would work like shown below (using another new feature, object initializers):
IEnumerable <MyType> result =
from s in aBunchOfWords
where s.Length == 5
select new MyType {Value=s, Length=s.Length, FirstThreeLetters=s.Substring(0,3)} ;
While I get the same results as in the previous example, you can see how var saves me the trouble of defining my own type. In the var example, the compiler is creating its own version of the "MyType" class, but you as a LINQ developer don't need to worry about that, but If you really don't like var, you can of course manually create your own class and map them to LINQ queries as I showed above and everything will still "just work".
When you're dealing with projection, var is awesome in that it really eliminates the grunt work of defining your own type, which, when you get to nested types can be pretty ugly :)
You can find a whole slew of projection operator samples at: https://msdn.microsoft.com/vcsharp/future/linqsamples/projection/default.aspx
Comments
Anonymous
September 22, 2005
The comment has been removedAnonymous
September 22, 2005
Its even cooler that you can also omit the field names and directly do a
var highlyPaid =
from e in employees
where e.Salary.Base > 10000
select new {e.Name, e.Salary.Base };
But since you cannot pass around var and its really really rare that you'll process all your data in the same method where you retrieved it using LINQ you'll anyway be forced to create a class to encapsulate the data to pass it back up to the callerAnonymous
September 22, 2005
Thank you, this example is way better than any other example I've seen of the use of 'var'. Using 'var' for ints, strings, or floats isn't really that interesting and it makes no logical sense why you would use 'var' in those cases, but your example definitely shows the power that it can have, thanksAnonymous
September 22, 2005
I have my doubts about the use of var for ints, strings, etc. too.
Why not restrict the use of var in C# 3.0 to LINQ constructs?Anonymous
September 22, 2005
Well i'm gonna say I don't like this var language construct. I can understand its uses in the context of annonymous types but for anything else it's worrying. I wouldn't want to see it used for say:
var x = someObject.SomeMethod()
The only way I would know what ‘x’ is in this context is to hover over it or go to the definition of 'SomeMethod'. It smacks of bad code readability to me. If for some reason 'SomeMethod' had its return type changed then there’s no easy way of seeing what the original ‘x’ was other than going to source control; Yuk! Maybe it would be a better idea to only allow ‘var’ to be used with annonymous types only.Anonymous
September 23, 2005
ben,
While it shows the power, I feel the term 'var' is going to cause all sorts of confusion. I believe many developers are going to see 'var' and think 'untyped' even though the variable is strongly typed. 'var' has a history and for this reason another term should be chosen.Anonymous
September 23, 2005
The comment has been removedAnonymous
September 26, 2005
I agree that the var keyword does remind one of variant and other horrible legacy stuff :-)
So maybe we should call it 'infer', because that is what happens.
infer a = new List<MyGeneric<OtherGeneric<int, string>>>();
Also as another example, it saves a lot of typing and repeating hereAnonymous
September 30, 2005
Hi Lee,
If someone changes the return type of the method to the point where it will break code that tries to access some property on this new anonymous type you've created (and now it's no longer there, as you are describing, the code won't compile. It's type-safe! That's the key here that people seem to be missing.Anonymous
January 09, 2006
I like the "infer" keyword as opposed to "var" but how about nothing. I have always hated the redundancy of typing:
DataGrid fred = new DataGrid();
Instead of something simpler like:
fred = new DataGrid();
where fred is infered to be a DataGrid.
especially where instead of DataGrid you have to see:
System.Windows.Form.Datagrid twice.
Call me heritical but I also believe that specifying parameters with types is reminiscent of C and unnecessary. Whatever is passed in is what it is. Automagically changing type is forbidden.Anonymous
June 09, 2006
Your demostration and opinion of why to use "vars" is great and i appreciate itAnonymous
April 21, 2007
PingBack from http://mdavey.wordpress.com/2007/04/21/initial-thoughts-on-orcas-beta1/Anonymous
January 23, 2008
There is a new type called var in C# 3.0. Var simply means that the compiler infers the type from whateverAnonymous
November 14, 2008
The comment has been removedAnonymous
November 18, 2008
The comment has been removedAnonymous
August 10, 2009
It seems to me that the only use of Linq to SQL is that you can get, within one subroutine, OOP-style access to data. Beyond that, one must still declare some their own classes and copy the data into instances before it can be passed around to other functions. If that's not the case, I'd really love to see an example. I have yet to see a code snippet that was more than a "hello world".Anonymous
November 12, 2009
Dan, this is exactly what I was looking for. I'm using this to project a complex business object collection into a BindingSource.DataSource which I pass back to a DataGridView - very productive and the code is much cleaner.Anonymous
June 16, 2014
Why is the following code not compiling am I missing out a declaration? using System.Collections.Generic; using System.Linq; using System.Text; namespace TestLoopOverInts { class Program { int[] numbers = { 10, 20, 30, 40, 1, 2, 3, 8 }; // get numbers less than ten var subset = from i in numbers where i < 10 select i; static void Main(string[] args) { } } }Anonymous
June 17, 2014
@Jonathan - The reason why is that you don't have the code inside of the Main{...} method. Once you put the code inside the Main method, it will work. namespace LinqQuestion { class Program { static void Main(string[] args) { //numbers and subset variables moved inside this Main Method // get numbers less than ten int[] numbers = { 10, 20, 30, 40, 1, 2, 3, 8 }; var subset = from i in numbers where i < 10 select i; foreach (var item in subset) { Console.WriteLine(item); } Console.Read(); } } }