Expression tree-Understanding and advanced

Source: Internet
Author: User

People who have just come into contact with LINQ often find expression trees very difficult to understand. Through this article I want you to see that it is not as difficult as it might seem. You can easily understand this article as long as you have common LINQ knowledge.

The expression tree provides a way to transform executable code into data. If you want to modify or transform this code before executing the code, it is very valuable. Especially when you want to convert C # code----such as a LINQ query expression to another code to manipulate it in another program----such as a SQL database.

But I'm reversing the order here, and at the end of the article you can easily see why it's useful to convert your code into data. First I need to provide a bit of background knowledge. Let's start by looking at the related simple syntax for creating an expression tree.

syntax of an expression tree


Consider the following simple lambda expression:


Func<int, int, int> function = (b) + A + B; This statement consists of three parts:
    1. A declaration: func<int, int, int> function
    2. An equal sign : =
    3. A lambda expression: (A, b) = + A + b;

The variable function points to a native executable code that adds two numbers. The above three-step lambda expression represents a short handwritten method as follows:
public int function (int a, int b) {return a + B;}
The above method or lambda expression can be called this way:

int c = function (3, 5);


When the method is called, the variable C is set to 3+5, which is 8.

The first step in the declaration of the delegate type Func is defined for us in the System namespace:

Public delegate TResult Func<t1, T2, tresult> (T1 arg1, T2 arg2);

This code looks complicated, but it's here to help us define the variable function, the variable function is assigned to a very simple two-digit lambda expression. Even if you don't understand delegates and generics, you should still be aware that this is a way to declare a reference to an executable code variable. In this example it points to a very simple executable code.

converting code into data

In the previous section, you saw how to declare a variable that points to the native executable code. An expression tree is not executable code, it is a data structure. So how do we convert from the native code of an expression to an expression tree? How do I convert from code to data?

LINQ provides a simple syntax for converting code to a data structure called an expression tree. First, add a using statement to introduce the Linq.expressions namespace:

Using System.Linq.Expressions;


Now we can create an expression tree:

Expression<func<int, int, int>> expression = (A, b) = a + B;

As in the previous example, a lambda expression is used to convert to an expression tree of type expression<t>. Identity expression is not executable code; it is a data structure called an expression tree.

Visual Studio 2008 's samples contains a call ExpressionTreeVisualizerThe program. It can be used to render an expression tree. Figure 1 You can see a dialog box showing the above simple expression statement. Note that the upper part of the dialog box shows a lambda expression, and the following is the component that is displayed with the TreeView control.


Figure 1:VS2008 of ExpressionTreeVisualizer in C # samples creating symbolic output of an expression tree

writing code to explore an expression tree

Our example is a expression<tdelegate>. The Expression<tdelegate> class has four properties:
    • body: Gets the body of the expression.
    • Parameters: Gets the parameters of the lambda expression.
    • NodeType: Gets the expressiontypeof the node of the tree. A total of 45 different values, including the various possible types of all expression nodes, such as returning constants, such as returning a parameter, such as taking a small value of two values (<), such as taking a large value of two values (>), such as adding values (+), and so on.
    • type: Gets a static type of the expression. In this example, the type of expression is Func<int, int, int>.

If we fold the tree node of Figure 1, the four properties of,expression<tdelegate> are clearly displayed:

Figure 2: You can easily see the four main properties of the Expression<tdelegate> class by collapsing the tree nodes.

You can use these four properties to start exploring the expression tree. For example, you can find the name of the parameter by doing this:

Console.WriteLine ("Parameter 1: {0}, Parameter 2: {1}", expression.) Parameters[0], expression. PARAMETERS[1]);

This code output value aAnd b

Parameter 1:a, parameter 2:b

This is easily found in the parameterexpression node of Figure 1.

Let's explore the body of the expression in the following code, in this case (A + B):

Binaryexpression BODY = (binaryexpression) expression. Body; ParameterExpression left = (parameterexpression) body. Left; ParameterExpression right = (parameterexpression) body. right; Console.WriteLine (expression. Body); Console.WriteLine ("Left part of expression:" + "{0}{4} node type: {1}{4} The right part of expression: {2}{4} type: {3}{4}". Name, body. NodeType, right. Name, body. Type, Environment.NewLine);

This code produces the following input:

(A + B)
Left part of expression: a
Node Type: ADD
The right part of an expression: b
Type: System.Int32

Again, you will find it easy to locate this information in the body node of Figure 1.

By exploring expression trees, we can analyze the parts of an expression to discover its composition. As you can see, all the elements of our expression are shown as data structures like nodes. The expression tree is the data that the code transforms into.

compiling an expression: converting data back to codeIf we can convert the code to data, we should also be able to convert the data back to the code. Here is a simple code that lets the compiler transform an expression tree into executable code.

int result = Expression.compile () (3, 5); Console.WriteLine (result);

This code will output a value of 8, just like the result of the lambda function that was originally declared in this article.

iqueryable<t> and expression trees

Now at least you have an abstract concept to understand the expression tree, it's time to come back to understand its key role in LINQ, especially in LINQ to SQL. Take some time to consider this standard LINQ to SQL query expression:

var query = from C in db. Customers where c.city = = "Nantes" select New {c.city, c.companyname};

As you might know, the variable query returned by the LINQ expression here is the IQueryable type. Here is the definition of the IQueryable type:

Public interface Iqueryable:ienumerable {Type ElementType {get;}  Expression expression {get;} Iqueryprovider Provider {get;}}

As you can see, IQueryable contains a property of type expression, and expression is the base class for expression<t>. An instance of IQueryable is designed to have a related expression tree. It is a data structure that is equivalent to the executable code in a query expression.

Take some time to consider Figure 3. You may need to click on it to make the picture original size display. This is the visual display of the expression tree for the query expression that starts in this section. This figure uses ExpressionTreeVisualizerCreated, just as I used it in Figure 1 to create the underlying lambda expression tree.

Figure 3: This complex expression tree is generated by the example LINQ to SQL query expression above. (Click on the image to see a larger image)

Why would you want to convert a LINQ to SQL query expression into an expression tree?

You have learned that an expression tree is a data structure used to represent executable code. But so far we have not answered a core question, that is why we have to do such a conversion. This is the question we brought up at the beginning of this article, and it is time to answer it.

A LINQ to SQL query is not executed in your C # program. Instead, it is converted to SQL, sent over the network, and finally executed on the database server. In other words, the following code is never actually executed in your program:

var query = from C in db. Customers

where c.city = = "Nantes"

Select New {c.city, c.companyname};

It is first converted to the following SQL statement and then executed on the server:

SELECT [T0]. [City], [t0]. [CompanyName] from [dbo]. [Customers] As [t0] WHERE [t0]. [City] = @p0

The code from the query expression is converted to a SQL query statement----It can be sent as a string to another program. Here, this program happens to be a SQL Server database. converting data structures to SQL like this is obviously much easier than converting directly from native IL or executable code to SQL. This is somewhat exaggerated in the difficulty of the problem, just imagine converting 0 and 1 sequences to sql!

Now it's time to convert your query expression to SQL, and the expression tree that describes the query is decomposed and parsed, just as we decomposed our simple lambda expression tree in the previous section. Of course, the algorithm for parsing the LINQ to SQL expression tree is much more complex than the one we use, but the rules are the same. Once the parts of the expression tree have been parsed, LINQ begins to consider the best way to generate the SQL statement that returns the requested data.

Expression trees are created to create a transformation task like converting a query expression into a string to pass to another program and doing so there. It's that simple. No great mystery, no need to wield a wand. It's simple: convert the code into data, then analyze the data to discover its components, and finally convert it into a string that can be passed to other programs.

Because the query comes from the abstract data structure that the compiler encapsulates, the compiler can get whatever information it wants. It does not require execution of queries to be in a particular order, or in a particular way. Instead, it can parse the expression tree, find out what you want to do, and then decide how to do it. At least theoretically, we are free to consider various factors, such as network conditions, database load, whether the result set is valid, and so on. In practice LINQ to SQL does not take all these factors into account, but it is theoretically free to do almost anything that you want to do. In addition, people can parse and translate their own code from the expression tree into something completely different than what LINQ to SQL provides.

iqueryable<t> and Ienumerable<t>

As you might know, the query expression for LINQ to objects returns ienumerable<t> instead of iqueryable<t>. Why does LINQ to Objects use Ienumerable<t> while LINQ to SQL uses Iqueryable<t>?

Here is the definition of ienumerable<t>:

Public interface ienumerable<t>: IEnumerable {ienumerator<t> GetEnumerator ();}

As you can see, the,ienumerable<t> does not contain attributes of type expression. This points to the fundamental difference between LINQ to Objects and LINQ to SQL. The latter used a large number of expression trees, but LINQ to Objects was seldom used.

Why is an expression tree not a standard part of LINQ to Objects? Although the answer may not appear immediately, it makes sense once you find the problem.

Consider this simple LINQ to Objects query expression:

list<int> list = new List<int> () {1, 2, 3};var query = from number in list where number < 3 Select number;

This LINQ query returns a number smaller than 3 in our list, which means that the numbers 1 and 2 are returned. It is clear that it is not necessary to convert the query into strings in order to pass to other programs and get the correct results. Instead, you can directly convert the query expression to executable. NET code. There is no need to convert it into a string or perform any other complex operations on it.

But this is a bit of a theory, in practice in some special cases, the separation line may be somewhat vague, the general rule is quite simple:

    • If the code can be executed in the program then you can complete the task using a simple type called ienumerable<t>
    • If you need to convert a query expression into a string that will be passed to another program, you should use the iqueryable<t> and expression trees.

Projects like LINQ to Amazon need to convert query expressions into Web service calls to execute external programs, typically using iqueryable<t> and expression trees. LINQ to Amazon transforms its query expression into data, passing it through a Web service to another program that is not even written in C #. The abstraction inherent in an expression tree is useful when converting C # code into something that can be passed to a Web service. Code that you want to execute within a program can still be used frequently and throw away the expression tree. For example, the following query uses IENUMERABLE&LT;T&GT, because it is called to the current program. NET Reflection API:

var query = from method in typeof (System.Linq.Enumerable). GetMethods ()

Method. Name

Group method by method. Name into G

Select New {Name = G.key, Overloads = G.count ()};

Profile

This article covers some of the basic conditions of the expression tree. By translating code into data, these data structures reveal and depict the components of an expression. In the smallest sense, it is fairly straightforward to understand an expression tree. It gets an executable expression and obtains its constituent parts into a tree-shaped data structure. For example, we detect this simple expression:

(b) = + A + b;

By studying the tree derived from this expression, you can see the basic rules for creating a tree, as shown in Figure 1.

You can also see that the expression tree plays a very important role in LINQ to SQL. In particular, they are data abstractions that LINQ to SQL query expressions use to get logic. Parse and parse this data to get the SQL statement and then send it to the server.

LINQ enables type checking and IntelliSense for querying a common class of the C # language. Its code is type-checking and IntelliSense and must use the correct C # syntax, which can be converted and executed directly into executable code, just like any other C # code. An expression tree makes it relatively easy to convert executable code into SQL statements that can be passed to the server.

The query returns ienumerable<t> better than iqueryable<t> means that the expression tree is not used. As a general rule, you can say that LINQ queries do not need an expression tree when executed within a program, and can take advantage of an expression tree when code executes outside of a program.

Note: This article is transferred from http://www.cnblogs.com/tianfan/

Expression tree-Understanding and advanced

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.