Skip to content

Instantly share code, notes, and snippets.

@holyqqwqqasd
Created February 21, 2024 08:57
Show Gist options
  • Save holyqqwqqasd/80f92ef23f7ef4d2518eb6fa3845a589 to your computer and use it in GitHub Desktop.
Save holyqqwqqasd/80f92ef23f7ef4d2518eb6fa3845a589 to your computer and use it in GitHub Desktop.
public static class ExpressionLogicalOperators
{
public static Expression<Func<T, bool>> And<T>(
Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var parameter = Expression.Parameter(typeof(T), expr1.Parameters[0].Name);
var left = ExpressionHelper.ReplaceParameter(expr1.Body, expr1.Parameters[0], parameter);
var right = ExpressionHelper.ReplaceParameter(expr2.Body, expr2.Parameters[0], parameter);
var body = Expression.AndAlso(left, right);
return Expression.Lambda<Func<T, bool>>(body, parameter);
}
public static Expression<Func<T, bool>> Or<T>(
Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var parameter = Expression.Parameter(typeof(T), expr1.Parameters[0].Name);
var left = ExpressionHelper.ReplaceParameter(expr1.Body, expr1.Parameters[0], parameter);
var right = ExpressionHelper.ReplaceParameter(expr2.Body, expr2.Parameters[0], parameter);
var body = Expression.OrElse(left, right);
return Expression.Lambda<Func<T, bool>>(body, parameter);
}
public static Expression<Func<T, bool>> Not<T>(Expression<Func<T, bool>> expr)
{
var parameter = Expression.Parameter(typeof(T), expr.Parameters[0].Name);
var body = Expression.Not(ExpressionHelper.ReplaceParameter(expr.Body, expr.Parameters[0], parameter));
return Expression.Lambda<Func<T, bool>>(body, parameter);
}
}
public static class ExpressionCompose
{
/// <summary>
/// Converts (f : A => B, g : B => C) into (A => C), inlining f body into g
/// </summary>
public static Expression<Func<TSource, TResult>> Compose<TSource, TIntermediate, TResult>(
Expression<Func<TSource, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
var param = Expression.Parameter(typeof(TSource), first.Parameters[0].Name);
var intermediateValue = ExpressionHelper.ReplaceParameter(first.Body, first.Parameters[0], param);
var body = ExpressionHelper.ReplaceParameter(second.Body, second.Parameters[0], intermediateValue);
return Expression.Lambda<Func<TSource, TResult>>(body, param);
}
}
internal static class ExpressionHelper
{
public static Expression ReplaceParameter(
Expression expression,
ParameterExpression toReplace,
Expression newExpression)
=> new ParameterReplaceVisitor(toReplace, newExpression).Visit(expression) ?? expression;
}
internal sealed class ParameterReplaceVisitor : ExpressionVisitor
{
private readonly ParameterExpression _from;
private readonly Expression _to;
public ParameterReplaceVisitor(ParameterExpression from, Expression to)
{
_from = from;
_to = to;
}
protected override Expression VisitParameter(ParameterExpression node) =>
node == _from ? _to : node;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment