Expression trees permit anonymous functions to be represented as data structures instead of executable code. Expression trees are values of expression tree types of the form System.Linq.Expressions.Expression<D>, where D is any delegate type. For the remainder of this specification we will refer to these types using the shorthand Expression<D>.
If a conversion exists from an anonymous function to a delegate type D, a conversion also exists to the expression tree type Expression<D>. Whereas the conversion of an anonymous function to a delegate type generates a delegate that references executable code for the anonymous function, conversion to an expression tree type creates an expression tree representation of the anonymous function.
Expression trees are efficient in-memory data representations of anonymous functions and make the structure of the anonymous function transparent and explicit.
Just like a delegate type D, Expression<D> is said to have parameter and return types, which are the same as those of D.
The following example represents an anonymous function both as executable code and as an expression tree. Because a conversion exists to Func<int,int>, a conversion also exists to Expression<Func<int,int>>:
Func<int,int> del = x => x + 1; // Code
Expression<Func<int,int>> exp = x => x + 1; // Data
Following these assignments, the delegate del references a method that returns x + 1, and the expression tree exp references a data structure that describes the expression x => x + 1.
The exact definition of the generic type Expression<D> as well as the precise rules for constructing an expression tree when an anonymous function is converted to an expression tree type, are both outside the scope of this specification, and are described elsewhere.
Two things are important to make explicit:
Not all anonymous functions can be represented as expression trees. For instance, anonymous functions with statement bodies, and anonymous functions containing assignment expressions cannot be represented. In these cases, a conversion still exists, but will fail at compile time.
Expression<D> offers an instance method Compile which produces a delegate of type D:
Func<int,int> del2 = exp.Compile();
Invoking this delegate causes the code represented by the expression tree to be executed. Thus, given the definitions above, del and del2 are equivalent, and the following two statements will have the same effect:
int i1 = del(1);
int i2 = del2(1);
After executing this code, i1 and i2 will both have the value 2.
Variables represent storage locations. Every variable has a type that determines what values can be stored in the variable. C# is a type-safe language, and the C# compiler guarantees that values stored in variables are always of the appropriate type. The value of a variable can be changed through assignment or through use of the ++ and ‑‑ operators.
A variable must be definitely assigned before its value can be obtained.
As described in the following sections, variables are either initially assigned or initially unassigned. An initially assigned variable has a well-defined initial value and is always considered definitely assigned. An initially unassigned variable has no initial value. For an initially unassigned variable to be considered definitely assigned at a certain location, an assignment to the variable must occur in every possible execution path leading to that location.