Original Article
Introducing LINQ—Language Integrated Query
By 19 May 2011
,
|
> predicate) { foreach (T item in source) { if (predicate(item)) yield return item; } }This extension method will apply to an object that extends the
IEnumerable
interface, and has one parameter of type Func
, which you can think of as a pointer to a function. This parameter function is the predicate to specify the criteria for the selection. This method will return a list of objects that match the predicate criteria.Now we can create a new function as the predicate:
public static bool IsVege(Product p)
{
return p.ProductName.Contains("vegetable");
}
Then we can use the Extension Method Get
to retrieve all of the vegetable products, like this:var veges1 = products.Get(IsVege);
In previous sections, we have created a products list, with five products, of which two are vegetables. So veges1
is actually of the IEnumerable
type, and should contain two products. We can write the following test statements to print out the results:Console.WriteLine("\nThere are {0} vegetables:", veges1.Count());
foreach (Product p in veges1)
{
Console.WriteLine("Product ID: {0} Product name: {1}",
p.ProductID, p.ProductName);
}
The output will be:
Or, we can first create a new variable of type
Func
, assign the function pointer of IsVege
to this new variable, and then pass this new variable to the Get
method, like this:Funcbool
> predicate = IsVege; var veges2 = products.Get(predicate);The variable veges2
will contain the same products as veges1
.Now, let us use the C# 2.0 anonymous method to rewrite the above statement, which will now become:
var veges3 = products.Get(
delegate (Product p)
{
return p.ProductName.Contains("vegetable");
}
);
At this time, we put the body of the predicate method IsVege
inside the Extension Method call, with the keyword delegate
. So, in order to get the vegetables from the products list, we don't have to define a specific predicate method. We can specify the criteria on the spot, when we need it.The lambda expression comes into play right after the above step. In C# 3.0, with lambda expression, we can actually write the following one line statement to retrieve all of the vegetables from the products list:
var veges4 = products.Get(p => p.ProductName.Contains("vegetable"));
In the above statement, the parameter of the method Get
is a lambda expression. The first p
is the parameter of the lambda expression, just like the parameter p
in the anonymous method when we get veges3
. This parameter is implicitly typed and, in this case, is of type Product
, because this expression is applied to a Products
object, which contains a list of Product
objects. This parameter can also be explicitly typed, like this:var veges5 = products.Get((Product p) => p.ProductName.Contains("vegetable"));
The parameter is followed by the =>
token, and then followed by an expression or a statement block, which will be the predicate.So, now we can easily write the following statement to get all of the candy products:
var candies = products.Get(p => p.ProductName.Contains("candy"));
At compile time, all lambda expressions are translated into anonymous methods according to the lambda expression conversion rules. So again, this feature is only a Visual Studio feature. We don't need any special .NET runtime library or instructions to run an assembly containing lambda expressions.In short, lambda expressions are just another way of writing anonymous methods in a more concise, functional syntax.
Built-in LINQ Extension Methods and method syntax
.NET Framework 3.5 defines lots of Extension Methods in the namespaceSystem.Linq
, including Where
, Select
, SelectMany
, OrderBy
, OrderByDescending
, ThenBy
, ThenByDescending
, GroupBy
, Join
, and GroupJoin
.We can use these Extension Methods just as we would use our own Extension Methods. For example, we can use the
Where
Extension Method to get all vegetables from the Products
list, like this:var veges6 = products.Where(p => p.ProductName.Contains("vegetable"));
This will give us the same result as veges1
through veges5
.As a matter of fact, the definition of the built-in LINQ Extension Method
Where
is just like our Extension Method Get
, but in a different namespace:namespace System.Linq
{
public static class Enumerable
{
public static IEnumerable Where(this IEnumerable
source, Funcbool
> predicate) { foreach (T item in source) { if (predicate(item)) yield return item; } } } }The statements that use LINQ Extension Methods are called using the LINQ method syntax.Unlike the other C# 3.0 new features that we have talked about in previous sections, these LINQ specific Extension Methods are defined in .NET Framework 3.5. So, to run an assembly containing any of these methods, you need .NET Framework 3.5 or above installed.
LINQ query syntax and query expression
With built-in LINQ Extension Methods and lambda expressions, Visual Studio allows us to write SQL-like statements in C# when invoking these methods. The syntax of these statements is called LINQ query syntax, and the expression in query syntax is called a query expression.For example, we can change this statement:
var veges6 = products.Where(p => p.ProductName.Contains("vegetable"));
to the following query statement, by using the new LINQ query syntax:var veges7 = from p in products
where p.ProductName.Contains("vegetable")
select p;
In the above C# statement, we can directly use the SQL keywords select
, from
, and where
to "query" an in-memory collection list. In addition to the in-memory collection lists, we can use the same syntax to manipulate data in XML files, in a dataset, and in a database. In the following articles, we will see how to query a database using LINQ to SQL and LINQ to Entities.Combined with the anonymous data type, we can shape the result of the query in the following statement:
var candyOrVeges = from p in products
where p.ProductName.Contains("candy")
|| p.ProductName.Contains("vegetable")
orderby p.UnitPrice descending, p.ProductID
select new { p.ProductName, p.UnitPrice };
As you have seen, query syntax is a very convenient, declarative shorthand for expressing queries using the standard LINQ query operators. It offers a syntax that increases the readability and clarity of expressing queries in code, and can be easy to read and write correctly.Not only is query syntax easy to read and write, Visual Studio actually provides complete intellisense and compile-time checking support for query syntax. For example, when typing in p and the following dot, we get all of the
Product
members listed in the intellisense list, as shown in the following image:
If there is a typo in the syntax (as is the case in this statement:
where p.productName.Contains("vegetable")
), the compiler will tell you exactly where the mistake is and why it is wrong. There won't be any run-time errors such as "invalid SQL statement". The following image shows the error message when there is a typo in the statement:
As you can see, you can write a LINQ statement in the query syntax, much like when you are working with a database in Query Analyzer. However, the .NET Common Language Runtime (CLR) has no notion of the query syntax. Therefore, at compile time, query expressions are translated to something that the CLR does understand: method calls. Under the covers, the compiler takes the query syntax expressions and translates them into explicit method invocation code that utilizes the new LINQ Extension Method and lambda expression language features in C# 3.0.
For example, the
candyOrVeges
query expression will be translated to this method invocation call:products.Where(p => p.ProductName.Contains("candy")
|| p.ProductName.Contains("vegetable")).OrderByDescending(
p => p.UnitPrice).ThenBy(p=>p.ProductID).Select(p=>new { p.ProductName, p.UnitPrice })
You can print out and compare the results for using query syntax and method syntax, to make sure they are equivalent. The following statements will print out the product name and unit price for the products in the query result using query syntax:foreach (var p in candyOrVeges)
{
Console.WriteLine("{0} {1}", p.ProductName, p.UnitPrice);
}
Do the same for the results using method syntax, and you will get a printout like this:
In general, query syntax is recommended over method syntax because it is usually simpler, and more readable. However, there is no semantic difference between method syntax and query syntax.
Built-in LINQ operators
As we have seen in the previous sections, there are no semantic differences between method syntax and query syntax. In addition, some queries, such as those that retrieve the number of elements matching a specified condition, or those that retrieve the element that has the maximum value in a source sequence, can be expressed only as method calls. These kinds of methods are sometimes referred to as .NET Standard Query Operators and includeTake
, ToList
, FirstOrDefault
, Max
, and Min
.In addition to those methods that can only be expressed as method calls, all the Extension Methods that can be used in either query syntax or method syntax are also defined as standard query operators such as
select
, where
, and from
. So, the .NET Standard Query Operators contain all of the LINQ-related methods.A complete list of these operators can be found at Microsoft MSDN library for the class
System.Linq.Enumerable
.To have a quick look at all those operators, in Visual Studio, open the program.cs file, and type in
System.Linq.Enumerable
. Then, type in a dot after Enumerable
. You will see the whole list of operators in the intellisense menu.
The methods in this static class provide an implementation of the standard query operators for querying data sources that implement
IEnumerable<(Of <(T>)>)
. The standard query operators are general-purpose methods that follow the LINQ pattern and enable you to express traversal, filter, and projection operations over data in any .NET-based programming language.The majority of the methods in this class are defined as Extension Methods that extend
IEnumerable<(Of <(T>)>)
. This means that they can be called like an instance method on any object that implements IEnumerable<(Of <(T>)>)
.Summary
In this article, we have learned new features related to LINQ, including the new data typevar
, object and collection initializers, Extension Methods, lambda expressions, LINQ syntax, and query expressions. Now that we have the required knowledge for LINQ, we are ready to try LINQ to SQL and LINQ to Entities, which will be discussed in the following articles.The key points covered in this article include:
- The new data type
var
gives extra flexibility when defining new variables - The Automatic Property feature can be used to define simple properties
- Initial values can be assigned to a new object and collection variables by using Object initializer and Collection initializer
- Actual types will be created for anonymous types at compile time
- Extension Methods can be used to extend the public contract of an existing CLR type, without having to subclass or recompile the original type
- Lambda expressions are just another way of writing anonymous methods in a more concise, functional syntax
- Many LINQ-specific Extension Methods have been pre-defined in .NET Framework 3.5
- All .NET Standard LINQ Query Operators are defined in the static class
System.Linq.Enumerable
- LINQ query syntax can be used to make expressions in method syntax, but there is no semantic difference between method syntax and query syntax
- Some LINQ queries can only be expressed in method calls
With this book, you can learn how to master WCF and LINQ to Entities concepts by completing practical examples and applying them to your real-world assignments. This is the first and only book to combine WCF and LINQ to Entities in a multi-tier real-world WCF Service. It is ideal for beginners who want to learn how to build scalable, powerful, easy-to-maintain WCF Services. This book is rich with example code, clear explanations, interesting examples, and practical advice. It is a truly hands-on book for C++ and C# developers.
You don't need to have any experience in WCF or LINQ to Entities to read this book. Detailed instructions and precise screenshots will guide you through the whole process of exploring the new worlds of WCF and LINQ to Entities. This book is distinguished from other WCF and LINQ to Entities books by that, this book focuses on how to do it, not why to do it in such a way, so you won't be overwhelmed by tons of information about WCF and LINQ to Entities. Once you have finished this book, you will be proud that you have been working with WCF and LINQ to Entities in the most straightforward way.
No comments:
Post a Comment
Comments?