In my previous Query Syntax blog post I demonstrated how you could
transform data with projections. This is a powerful feature of LINQ that
enables you to perform query operations on a data source (regardless of whether
it is a database, an XML file, or an in-memory collection), and shape the
results of the data being queried into a different structure/format than the
original data source is in.
In my previous Query Syntax blog post I defined a custom
"MyProduct" class that I used to represent my transformed product
data. By explicitly defining the "MyProduct" class I have a
formal CLR type contract that I can use to easily pass my custom-shaped product
results between web-services or between multiple classes/assemblies within my
application solution.
However, there are times when I just want to query and work
with data within my current code scope, and I don't want to have to formally
define an explicit class that represents my data in order to work
with it. This is where anonymous types are very useful, as they allow you
to concisely define a new type to use inline within your code.
For example, assume I use the LINQ to SQL object
relational mapper designer within "Orcas" to model the "Northwind"
database with classes like below:
Figure 1
I can then use the below code to query the Product data in
my database, and use the projection/transformation capability of LINQ to custom
shape the data result to be something other than the "Product" class
above. Rather than use an explicitly defined "MyProduct" class
to represent each custom-shaped row of data retrieved from the database, I can
instead use the anonymous type feature to implicitly define a new type with
four properties to represent my custom shaped data like so:
Figure 2
In the code above I'm declaring an anonymous type as part of
the select clause within my LINQ expression, and am having the compiler
automatically create the anonymous type with 4 properties (Id, Name, UnitPrice
and TotalRevenue) - whose property names and type values are inferred from the
shape of the query.
I'm then using the new "var" keyword within C# to
programmatically refer to the IEnumerable<T> sequence of this anonymous
type that is returned from the LINQ expression, as well as to refer to each of
the anonymous type instances within this sequence when I programmatically loop
over them within a foreach statement later in my code.
While this syntax gives me dynamic language-like
flexibility, I also still retain the benefits of a strongly-typed language
- including support for compile-time checking and code intellisense
within Visual Studio. For example, notice above how I am doing a
foreach over the returned products sequence and I am still able to get
full code intellisense and compilation checking on the anonymous type with
custom properties that was inferred from the LINQ query.