-
Notifications
You must be signed in to change notification settings - Fork 4
Home
When writing regular methods and delegates via .NET it's easy to (re)use them from each other. Expressions however are not so easy. Lambda syntax doesn't allow you using one expression inside another one out of the box. If you use Compile method inside an expression to get a delegate that you may then call, such an expression will not be supported by most LINQ providers.
Mindbox.Expressions library allows you to include lambda expressions into each other and transform the result into a plain expression translatable to LINQ-to-SQL, Entity Framework or whatever you need.
Use Evaluate method to include expressions into each other:
Expression<Func<int, int>> squareExpression = x => x * x;
Expression<Func<int, int, int>> squareSumExpression = (x, y) =>
squareExpression.Evaluate(x) + squareExpression.Evaluate(y);
Alternatively you can use Compile()
method instead:
Expression<Func<int, int, int>> squareSumExpression = (x, y) =>
squareExpression.Compile()(x) + squareExpression.Compile()(y);
Or even:
Expression<Func<int, int, int>> squareSumExpression = (x, y) =>
squareExpression.Compile().Invoke(x) +
squareExpression.Compile().Invoke(y);
Save the resulting expression to a variable and call ExpandExpressions()
method on it:
Expression<Func<int, int, int>> squareSumExpression = (x, y) =>
squareExpression.Evaluate(x) + squareExpression.Evaluate(y);
var expandedExpression = squareSumExpression.ExpandExpressions();
You get expanded expression containing just
(x, y) => (x * x) + (y * y);
Or better use it in IQueryable methods and call ExpandExpressions()
method on resulting IQueryable<>
before it gets enumerated (or translated in any other way):
IQueryable<Human> query = ...;
Expression<Func<Human, bool>> isGirlExpression = ...;
Expression<Func<Human, int>> ageExpression = ...;
var result = query
.Where(human => isGirlExpression.Evaluate(human) &&
(ageExpression.Evaluate(human) >= 18))
.OrderBy(human => human.Name)
.ExpandExpressions()
.ToList();
Often you just need to combine boolean expressions with same parameters via AndAlso
(&&
) or OrElse
(||
). You can do it via extension methods:
Expression<Func<Human, bool>> isGirlExpression = ...;
var combinedViaAndAlso =
isGirlExpression.AndAlso(human => human.Age >= 18);
Or if you have a non-empty collection of such expressions, you can combine them all at once:
IEnumerable<Expression<Func<Human, bool>>> expressions = ...;
var combinedViaAndAlso =
BooleanExpressions.CombineViaAndAlso(expressions);
Visual Studio and other code editors support automated refactorings allowing you, for example, to rename class members. However sometimes we do not reference class members in code directly but access or reference them via reflection by name. But names are just strings and automated tools cannot handle them.
ReflectionExpressions
class allows you to reference class members by building an expression referencing them. Expressions are just code so the tools can handle them.
To get MethodInfo
of an instance method (or an extension method):
class SomeClass
{
string GetSomething(int x, double y);
}
var methodInfo = ReflectionExpressions.GetMethodInfo<SomeClass>(
someClass => someClass.GetSomething(
default(int),
default(double));
To get MethodInfo
of a static method:
class SomeClass
{
static string GetSomething(int x, double y);
}
var methodInfo = ReflectionExpressions.GetMethodInfo(
() => SomeClass.GetSomething(
default(int),
default(double));
If you need just a name, you can use GetMethodName
methods. If you aren't sure the expression you use is valid, you can use TryGetMethodInfo
and TryGetMethodName
methods.
The same for properties and fields:
GetPropertyInfo
GetPropertyName
TryGetPropertyInfo
TryGetPropertyName
GetFieldInfo
GetFieldName
TryGetFieldInfo
TryGetFieldName