Page 45 - MSDN Magazine, September 2019
P. 45

1. equality test, of
2. the addition of 5. and the fixed value 27
4. the fixed value 42
Figure 2 Expression Tree Objects Using Object Notation
‘ Visual Basic
New BinaryExpression With {
.NodeType = ExpressionType.Equal, .Left = New BinaryExpression With {
.NodeType = ExpressionType.Add,
.Left = New ParameterExpression With {
.Name = "n" },
.Right = New ConstantExpression With { .Value = 42
} },
.Right = New ConstantExpression With { .Value = 27
} }
// C#
new BinaryExpression {
NodeType = ExpressionType.Equal, Left = new BinaryExpression {
NodeType = ExpressionType.Add, Left = new ParameterExpression {
Name = "n" },
Right = new ConstantExpression { Value = 42
} },
Right = new ConstantExpression { Value = 27
} }
3. the value identified by n, and
Figure 1 Breakdown of an Expression Tree
.NET provides a set of types in the System.Linq.Expressions namespace for constructing data structures that represent expres- sion trees. For example, n + 42 = 27 can be represented with objects and properties as shown in Figure 2. (Note that this code will not compile—these types don’t have public constructors, and they’re immutable, so no object initializers.)
The term expression tree in .NET is used for both syntactical expression trees (x + y), and expression tree objects (a Binary- Expression instance).
To understand what a given node in the expression tree represents, the node object’s type—BinaryExpression, ConstantExpression, ParameterExpression—only describes the shape of the expression. For example, the BinaryExpression type tells me that the represented expression has two operands, but not which operation com- bines the operands. Are the operands added together, multiplied together or compared numerically? That information is contained in the NodeType property, defined in the Expression base class. (Note that some node types don’t represent code operations—see “Meta Node Types.”)
An additional property of note on Expression is the Type property. In both Visual Basic and C#, every expression has a type—adding two Integers will produce an Integer, while adding two Doubles will produce a Double. The Type property returns the System.Type of the expression.
When visualizing the structure of an expression tree, it’s useful to focus on these two properties, as depicted in Figure 3.
If there are no public constructors for these types, how do we createthem?Youhavetwochoices.Thecompilercangeneratethem for you if you write lambda syntax where an expression type is expected. Or you can use the Shared (static in C#) factory meth- ods on the Expression class.
Constructing Expression Tree Objects I:
Using the Compiler
The simple way to construct these objects is to have the compiler generate them for you, as mentioned previously, by using lambda syntax anywhere an Expression(Of TDelegate) (Expression<TDel- egate> in C#) is expected: either assignment to a typed variable, or as an argument to a typed parameter. Lambda syntax is intro- duced in Visual Basic using either the Function or Sub keywords, followed by a parameter list and a method body; in C# the => operator indicates lambda syntax.
msdnmagazine.com
Lambda syntax that defines an expression tree is called an expression lambda (as opposed to a statement lambda), and looks like this in C#:
Expression<Func<Integer, String>> expr = i => i.ToString();
IQueryable<Person> personSource = ... var qry = qry.Select(x => x.LastName);
And like this in Visual Basic:
Dim expr As Expression(Of Func(Of Integer, String)) = Function(i) i.ToString
Dim personSource As IQueryable(Of Person) = ... Dim qry = qry.Select(Function(x) x.LastName)
Producing an expression tree in this way has some limitations: • Limited by lambda syntax
• Supports only single-line lambda expressions, with no
multiline lambdas
• Expression lambdas can only contain expressions, not
statements such as If...Then or Try...Catch
• No late binding (or dynamic in C#)
• In C#, no named arguments or omitted optional arguments • No null-propagation operator
The complete structure of the constructed expression tree—that is, node types, types of sub-expressions and over- load resolution of methods— is determined at compile time. Because expression trees are immutable, the structure can- not be modified once created.
Note also that compiler- generated trees mimic the
Figure 3 NodeType, Type, Value and Name Properties
September 2019 37


































































































   43   44   45   46   47