detect/detect.gui/Commons/PredicateBuilder.cs
2024-11-13 17:09:15 +08:00

63 lines
1.9 KiB
C#

using System;
using System.Linq.Expressions;
namespace detect.gui.Commons;
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> GetTrue<T>()
{
return f => true;
}
public static Expression<Func<T, bool>> GetFalse<T>()
{
return f => false;
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first,
Expression<Func<T, bool>> second)
{
return first.AndAlso(second, Expression.AndAlso);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first,
Expression<Func<T, bool>> second)
{
return first.AndAlso(second, Expression.OrElse);
}
private static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2, Func<Expression, Expression, BinaryExpression> func)
{
var parameter = Expression.Parameter(typeof(T));
var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
var left = leftVisitor.Visit(expr1.Body);
var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
var right = rightVisitor.Visit(expr2.Body);
if (left == null || right == null)
return Expression.Lambda<Func<T, bool>>(() => true);
return Expression.Lambda<Func<T, bool>>(func(left, right), parameter);
}
private class ReplaceExpressionVisitor : ExpressionVisitor
{
private readonly Expression? _oldValue;
private readonly Expression? _newValue;
public ReplaceExpressionVisitor(Expression? oldValue, Expression? newValue)
{
_oldValue = oldValue;
_newValue = newValue;
}
public override Expression? Visit(Expression? node)
{
return node == _oldValue ? _newValue : base.Visit(node);
}
}
}