Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
The Dynamic Expression API relies on a simple expression language for formulating
expressions and queries in strings.
specifies the required result type for the expression. The values parameter supplies
zero or more substitution values that may be referenced in the expression.
The example
ParameterExpression x = Expression.Parameter(typeof(int), "x");
ParameterExpression y = Expression.Parameter(typeof(int), "y");
LambdaExpression e = DynamicExpression.ParseLambda(
new ParameterExpression[] { x, y }, null, "(x + y) * 2");
creates and assigns an Expression<Func<int, int, int>> instance to e representing
the expression (x + y) * 2. If a required result type is specified, as in
LambdaExpression e = DynamicExpression.ParseLambda(
new ParameterExpression[] { x, y }, typeof(double), "(x + y) * 2");
the parsing operation will include an implicit conversion to the given result type, in
this case yielding an Expression<Func<int, int, double>> instance.
The second ParseLambda overload parses a lambda expression with a single
unnamed parameter of a specified argumentType. This method corresponds to
calling the first ParseLambda overload with a parameters argument containing a
single ParameterExpression with an empty or null Nameproperty.
When parsing a lambda expression with a single unnamed parameter, the members
of the unnamed parameter are automatically in scope in the expression string, and
the current instance given by the unnamed parameter can be referenced in whole
using the keyword it. The example
LambdaExpression e = DynamicExpression.ParseLambda(
typeof(Customer), typeof(bool),
"City = @0 and Orders.Count >= @1",
"London", 10);
creates and assigns an Expression<Func<Customer, bool>> instance to e. Note
that City and Orders are members of Customer that are automatically in scope. Also
note the use of substitution values to supply the constant values "London" and 10.
The third ParseLambda overload is a genericly typed version of the second
overload. The example below produces the
same Expression<Func<Customer, bool>> instance as the example above, but is
statically typed to that exact type.
Expression<Func<Customer, bool>> e =
DynamicExpression.ParseLambda<Customer, bool>(
"City = @0 and Orders.Count >= @1",
"London", 10);
Substitution Values
Several methods in the Dynamic Expression API permit substitution values to be
specified through a parameter array. Substitution values are referenced in an
expression using identifiers of the form @x, where x is an index into the parameter
array. The last element of the parameter array may be an object that
implements IDictionary<string, object>. If so, this dictionary is used to map
identifiers to substitution values during parsing.
An identifier that references a substitution value is processed as follows:
Expression Language
The expression language implemented by the Dynamic Expression API provides a
simple and convenient way of writing expressions that can be parsed into LINQ
expression trees. The language supports most of the constructs of expression trees,
but it is by no means a complete query or programming language. In particular, the
expression language does not support statements or declarations.
The expression language is designed to be familiar to C#, VB, and SQL users. For
this reason, some operators are present in multiple forms, such as && and and.
Identifiers
Literals
The expression language supports integer, real, string, and character literals.
An integer literal consists of a sequence of digits. The type of an integer literal is the
first of the types Int32, UInt32, Int64, or UInt64 that can represent the given value.
An integer literal implicitly converts to any other numeric type provided the number
is in the range of that type. Some examples of integer literals:
0 123 10000
"""quoted""" "'"
Constants
The predefined constants true and false denote the two values of the type Boolean.
The predefined constant null denotes a null reference. The null constant is of
type Object, but is also implicitly convertible to any reference type.
Types
Boolean
UInt16
Double
Char
Int32
DateTime
String
UInt32
TimeSpan
SByte
Int64
Guid
The primitive types correspond to the similarly named types in the System
namespace of the .NET Framework Base Class Library. The expression language also
defines a set of accessible types consisting of the primitive types and the following
types from the System namespace:
Math
Convert
The accessible types are the only types that can be explicitly referenced in
expressions, and method invocations in the expression language are restricted to
methods declared in the accessible types.
The nullable form of a value type is referenced by writing a ? after the type
name. For example, Int32? denotes the nullable form of Int32.
The non-nullable and nullable forms of the
types SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, and UInt64 are collectively
called the integral types.
The non-nullable and nullable forms of the types Single, Double, and Decimal are
collectively called the real types.
The integral types and real types are collectively called the numeric types.
Conversions
The following conversions are implicitly performed by the expression language:
From the the null literal to any reference type or nullable type.
From an integer literal to an integral type or real type provided the number is
within the range of that type.
From a real literal to a real type provided the number is within the range of
that type.
From a string literal to an enum type provided the string literal contains the
name of a member of that enum type.
From a source type that is assignment compatible with the target type
according to the Type.IsAssignableFrom method in .NET.
From a non-nullable value type to the nullable form of that value type.
The expression language permits explicit conversions using the syntax type(expr),
where type is a type name optionally followed by ? and expr is an expression. This
syntax may be used to perform the following conversions:
Operators
The table below shows the operators supported by the expression language in order
of precedence from highest to lowest. Operators in the same category have equal
precedence. In the table, x, y, and z denote expressions, T denotes a type,
and m denotes a member.
Categor Expression Description
y
Primary
x.m
x.m()
x[]
T.m
T.m()
Unary
T()
new()
it
x()
iif(x, y, z)
-x
!x
not x
Multiplica x * y
tive
Additive
x/y
x%y
x mod y
x+y
xy
x&y
Relationa x = y
l
x == y
x != y
x <> y
x<y
x>y
x <= y
x >= y
x && y
x and y
Logical
OR
x || y
x or y
Condition x ? y : z
al
A data object initializer creates a data class and returns an instance of that class.
The properties of the data class are inferred from the data object initializer.
Specifically, a data object initializer of the form
new(e1 as p1, e2 as p2, e3 as p3)
creates a data class with three properties, p1, p2, and p3, the types of which are
inferred from the expressions e1, e2, and e3, and returns an instance of that data
class with the properties initialized to the values computed by e1, e2, and e3. A
property initializer may omit the as keyword and the property name provided the
associated expression is a field or property access. The example
customers.Select("new(CompanyName as Name, Phone)");
creates a data class with two properties, Name and Phone, and returns a sequence
of instances of that data class initialized from
the CompanyName and Phone properties of each customer.
Current Instance
When parsing a lambda expression with a single unnamed parameter, the members
of the unnamed parameter are automatically in scope in the expression string, and
the current instance given by the unnamed parameter can be referenced in whole
using the keyword it. For example,
customers.Where("Country = @0", country);
is equivalent to
customers.Where("it.Country = @0", country);
The IQueryable extension methods all parse their expression arguments as lambda
expressions with a single unnamed parameter.
operators
seq . Any ( )
seq . Count ( )
seq . Min ( selector )
seq . Sum ( selector )
In the predicate and selector expressions, the members of the current instance for
that sequence operator are automatically in scope, and the instance itself can be
referenced using the keyword it. An example:
customers.Where("Orders.Any(Total >= 1000)");