Источник - ответ на StackOverflow, который сам является пересказом статьи

Дата: 2019-10-06


An expression tree represents what you want to do, not how you want to do it.

Consider the following very simple lambda expression:

Func<int, int, int> function = (a, b) => a + b;

This statement consists of three sections:

A declaration: Func<int, int, int> function An equals operator: = A lambda expression: (a, b) => a + b; The variable function points at raw executable code that knows how to add two numbers.

This is the most important difference between delegates and expressions. You call function (a Func<int, int, int>) without ever knowing what it will do with the two integers you passed. It takes two and returns one, that’s the most your code can know.

In the previous section, you saw how to declare a variable that points at raw executable code. Expression trees are not executable code, they are a form of data structure.

Now, unlike delegates, your code can know what an expression tree is meant to do.

LINQ provides a simple syntax for translating code into a data structure called an expression tree. The first step is to 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;

The identical lambda expression shown in the previous example is converted into an expression tree declared to be of type Expression. The identifier expression is not executable code; it is a data structure called an expression tree.

That means you can’t just invoke an expression tree like you could invoke a delegate, but you can analyze it. So what can your code understand by analyzing the variable expression?

// `expression.NodeType` returns NodeType.Lambda.// `expression.Type` returns Func<int, int, int>.// `expression.ReturnType` returns Int32.var body = expression.Body;// `body.NodeType` returns ExpressionType.Add.// `body.Type` returns System.Int32.var parameters = expression.Parameters;// `parameters.Count` returns 2.var firstParam = parameters[0];// `firstParam.Name` returns "a".// `firstParam.Type` returns System.Int32.var secondParam = parameters[1].// `secondParam.Name` returns "b".// `secondParam.Type` returns System.Int32.

Here we see that there is a great deal of information we can get from an expression.

But why would we need that?

You have learned that an expression tree is a data structure that represents executable code. But so far we have not answered the central question of why one would want to make such a conversion. This is the question we asked at the beginning of this post, and it is now time to answer it.