Overview
Beta2 of Orcas has shipped yesterday. You can download it either as a standalone-download, or as a VPC. Of course THE biggest feature in Orcas that everybody keeps talking about is LINQ. LINQ is a methodology that simplifies and unifies the implementation of any kind of data access. LINQ does not force you to use a specific architecture; it facilitates the implementation of several existing architectures for accessing data.
In .NET 3.5 LINQ is made possible because of a number of new technologies:
- A net set of assemblies that are based upon .NET 2.0
- A number of powerful new features in the C# 3.0 language.
In the series of blog entries, I would like to take a look at these enabling C# 3.0 features.W e will look at each feature in turn, and in our downloads section, we will provide a small sample for each covered feature.
Once you get a feel for these new features, not only will you have as easier way integrating LINQ into your application, but you will also be able to use these powerful features in your own programming situations, independent of LINQ. And of course, look to this blog for extensive coverage of LINQ and the other new features in Orcas (such as the improved WF and WCF integration) soon!
A 30,000 feet view of Orcas
Before we begin our coverage, it is important to note that when you build a C# 3.0 program, this program will still be executing on the good old .NET 2.0 CLR. Indeed, no changes were required to the CLR to facilitate LINQ, or any of the features outlined in this series of posts. I think this is a real compliments to the resilience of the .NET CLR! On the other hand, it get's kind of hard to explain what is part of the redistributable's of Orcas, and the different compilers and .Net assemblies involved. After all you will have:
- The "good old" .NET 2.0 assemblies that we all know and love.
- The .NET 3.0 assemblies, which cover the new "foursome" that we love to play with so much (WCF, WF, WPF and WCS).
- The new .NET 3.5 assemblies, which implement the brand new features, such as LINQ.
When you use the New Project wizard in Orcas, it actually provides a drop drop in the upper left corner, which lets you select the version of the .NET framework that you are targeting, as is shown below:

Of course, some features such as LINQ will be unavailable if you target the 2.0 compiler, but it is nice that you can use the nice new Orcas environment to target the "good old" .NET 2.0 or 3.0 frameworks.
Extensions to the C# Type system
Implicitly typed local variables ("var")
Old Style Declarations
In previous versions of C#, you always had to specify the data type of a variable when declaring the variable. For example, this was valid syntax for a method-scoped variable:
int beersConsumedByMatt;
You could also directly initialize the variable as so:
int beersConsumedByMatt = 5;
In general, the syntax for a declaration is:
<datatype> <variablename> [= <initializer>];
In the above discussion, the important point is that at any point in time we know the exact data type of beersConsumedByMatt, which is this case is a Long. (or System.Int32 for the CLR).
Implicitly typed Local Variables
Now, in C# 3.0 I can write a statement like this (at method scope):
var beersConsumedByJeremy = 15;
Notice the "var" keyword. "var" is a C# keyword that results in our variable to be of the same data type as the initializer, in this case an int, so in this case the above statement results in the creating of a local variable called beersConsumedByJeremy, which has a data type of "integer" (or System.Int32). We call beersConsumedByJeremy an implicitly typed local variable.
Now, for some old COM rats, this might bring back very bad memories to the "Variant" data type! Please do not break out in hives, do not start having nightmares! The Variant type was a memory hog, which occupied a lot of memory, and was not strong typed.
In contrast, a variable declared with the "var" keyword will immediately be strongly typed. The compiler will look at the initializer (which is NOT optional, and cannot be null), and match it to the closed possible data type for you. So, in our case, the compiler will assign the type of int to our beersConsumedByJeremy variable.
You can also create an implicitly typed local array. In this case, the compiler will look at the elements contained in the initializer, and set the base type of the array accordingly.
Below is a complete sample of implicitly typed local variables from the corresponding download:
1 private static void implicitlyTypedVariablesDemo()
2 {
3 Console.WriteLine("----- Start of Implicitly Typed Variables -----");
4
5 // C# 2.0 notation
6 long beersConsumedByMatt = 5;
7 Console.WriteLine("Type of beersConsumedByMatt: " + beersConsumedByMatt.GetType());
8
9 // C# 3.0 implicitly-typed variable
10 var beersConsumedByJeremy = 15;
11 Console.WriteLine("Type of beersConsumedByJeremy: " + beersConsumedByJeremy.GetType());
12
13 // C# 3.0 Implicitly-typed array
14 var myArray = new[] {1.2, 6.3, 7.1, 9.4, 4.2 };
15 Console.WriteLine("Type of myArray: " + myArray.GetType());
16 for (int i = 0; i < myArray.Length; i++)
17 {
18 Console.WriteLine("\tArray Element: {0}, value: {1}, Type: {2}",
19 i, myArray
, myArray
.GetType());
20 }
21
22 Console.WriteLine("----- End of Implicitly Typed Variables -----");
23 }
24
The output of the function is shown below:

Reasoning for having Implicitly Typed Local Variables
Now, why go through all of this fuss? What advantage do implicitly typed local variables give us, and especially, what are there benefits in connection to LINQ?
Let's take a look at the function below:
1 private static void whyImplicitlyTypedVariables()
2 {
3 string[] words = { "apple", "strwawberry", "grape", "peach", "banana" };
4 IEnumerable<String> wordQuery =
5 from word in words
6 where word[0] == 'g'
7 select word;
8 foreach (string word in wordQuery)
9 {
10 Console.WriteLine("\tWord:{0}", word);
11 }
12
13 // Example #2: var is required.
14 Customer[] customers =
15 { new Customer { CustomerId = 12, Name = "Bennie Haelen"},
16 new Customer { CustomerId = 20, Name = "Matt Ortiz" },
17 new Customer { CustomerId = 120, Name = "Pete Miller" }
18 };
19
20 var customerQuery = from cust in customers
21 where cust.CustomerId < 100
22 select new { cust.CustomerId, cust.Name };
23 foreach (var item in customerQuery)
24 {
25 Console.WriteLine("CustomerID={0}, Name={1}", item.CustomerId, item.Name);
26 }
27 }
28
In the first example (lines 2 through 10), we have no need to use a implicitly typed local variable, since our query returns a "word", which we know is of type string. Therefore, we can use IEnumerable<String> as the query result of our first query.
In the second example (lines 14 through 26), we MUST use a var as the result of the query, since the query returns an array of anonymous types ( select new { cust.CustomerId, cust.Name } ). We will talk more about anonymous types later in this series. Also, note that when we display our results in the foreach enumeration we have to use a var, because the type of each item is not available until the compiler determines it at runtime.
The output of this sample is shown below:

Note that we do not see the Customer instance with CustomerID = 120, since our query restricts the results to all customers with an ID less than 100.
You can get a sample with this code from this location. Any comments and feedback is always welcome!
Technorati Tags:
C# 3.0,
.NET 3.5,
LINQ