Language Integration


Language integration is a fundamental aspect of LINQ. The most visible part is the query expression feature, which is present in C# 3.0 and Visual Basic 9.0. It allows you to write code such as the following:

 var query =     from    c in Customers     where   c.Country == "Italy"     orderby c.Name     select  new { c.Name, c.City };

instead of writing this code:

 var query =         Customers         .Where( c => c.Country == "Italy" );         .OrderBy( c => c.Name )         .Select( c => new { c.Name, c.City } );

Many people call this simplification syntax sugaring because it is just a simpler way to write code that defines a query over data. However, there is more to it than that. Many language constructs and syntaxes are necessary to support what seems to be just a few lines of code that query data. Under the cover of this simple query expression are local type inference, extension methods, lambda expressions, object initialization expressions, and anonymous types. All of these features are useful by themselves, but if you look at the overall picture you should see that there is a big step in two directions: one moving to a more declarative style of coding, and one lowering the impedance mismatch between data and code.

Declarative Programming

What are the differences between an SQL query and an equivalent C# 2.0 or Visual Basic 8.0 program that filters data contained in native storage (such as a table for SQL or an array for C# or Visual Basic)?

In SQL, you can write the following:

 SELECT * FROM Customers WHERE Country = 'Italy'

In C#, you would probably write this:

 public List<Customer> ItalianCustomers( Customer customers[] )  {     List<Customer> result = new List<Customer>();     foreach( Customer c in customers ) {         if (c.Country == "Italy") result.Add( c );     }     return result; }

C# code takes longer to write and read. But the most important consideration is expressivity. In SQL, you describe what you want. In C#, you describe how to obtain the expected result. In SQL, the selection of the best algorithm to implement the how (which is more explicitly dealt with in C#) is the responsibility of the query engine. This is because the SQL query engine has more freedom to apply optimizations than a C# compiler, which has many more constraints on the how.

Note 

The previous C# code sample could be written in .NET 2.0 using a Find predicate, but for many developers the required anonymous delegate syntax is not very easy to use. However, the samples are merely illustrative of the different programming paradigms.

LINQ enables a more declarative style of coding for C# and Visual Basic. A LINQ query describes operations on data through a declarative construct instead of an iterative one. LINQ allows the intentions of programmers to be made more explicit, and this knowledge of programmer intent is fundamental to obtaining a higher level of services from the underlying framework. For example, think about parallelization. An SQL query can be split into several concurrent operations, simply because it does not place any constraint on the kind of table scan algorithm applied. A C# foreach loop is harder to split into several loops over different parts of an array that could be executed in parallel by different processors.

More Info 

Parallel LINQ (PLINQ) is a research project on the parallelism that can be obtained by writing code with LINQ.

Declarative programming can take advantage of services offered by compilers and frameworks, and in general it is easier to read and maintain. This single “feature” can be the most important one because it boosts programmers’ productivity. For example, suppose that you want to get a list of all static methods available in the current application domain that return an IEnumerable<T> interface. You can use LINQ to write a query over Reflection:

 var query =     from    assembly in AppDomain.CurrentDomain.GetAssemblies()     from    type in assembly.GetTypes()     from    method in type.GetMethods()     where   method.IsStatic             && method.ReturnType.GetInterface( "IEnumerable`1" ) != null     orderby method.DeclaringType.Name, method.Name     group   method by new { Class = method.DeclaringType.Name,                             Method = method.Name };

The equivalent C# code that handles data is longer to write, harder to read, and probably more error prone. You can see a possible version that is not particularly optimized in Listing 1-10.

Listing 1-10: C# code equivalent to a LINQ query over Reflection

image from book
  List<String> results = new List<string>(); foreach( var assembly in AppDomain.CurrentDomain.GetAssemblies()) {     foreach( var type in assembly.GetTypes() ) {         foreach( var method in type.GetMethods()) {             if (method.IsStatic &&                 method.ReturnType.GetInterface("IEnumerable`1") != null) {                 string fullName = String.Format( "{0}.{1}",                                       method.DeclaringType.Name,                                       method.Name );                 if (results.IndexOf( fullName ) < 0) {                     results.Add( fullName );                 }             }         }     } } results.Sort(); 
image from book

Type Checking

Another important aspect of language integration is type checking. Whenever data is manipulated by LINQ, no unsafe cast is necessary. The short syntax of a query expression has no compromises with type checking: data is always strongly typed, including both the queried collections and the single entities that are read and returned.

The type checking of the languages that support LINQ (currently C# 3.0 and Visual Basic 9.0) is preserved even when LINQ-specific features are used. This enables the use of Visual Studio features such as IntelliSense and Refactoring, even with LINQ queries. These Visual Studio features are very important for programmers’ productivity.

Transparency Across Different Type Systems

When you think about the type system of the Microsoft .NET Framework and the type system of SQL Server, you realize that they are different. Using LINQ, you give precedence to the .NET type system because it is the one supported by any language that hosts a LINQ query. However, most of your data will be saved in a relational database, and it is necessary to convert many types of data between these two worlds. LINQ handles this conversion for you automatically, making the differences in type systems almost completely transparent to the programmer.

More Info 

Some limitations exist in the capability to perform conversions between different type systems and LINQ. You will find some information about this topic in Chapter 5, and you can find a more detailed type system compatibilities table in the product documentation.




Introducing Microsoft LINQ
Introducing MicrosoftВ® LINQ
ISBN: 0735623910
EAN: 2147483647
Year: 2007
Pages: 78

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net