using System;
using System.Linq;
using System.Linq.Expressions;
namespace Abp.Specifications
{
///
/// Represents the extender for Expression[Func[T, bool]] type.
/// This is part of the solution which solves
/// the expression parameter problem when going to Entity Framework.
/// For more information about this solution please refer to http://blogs.msdn.com/b/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx.
///
public static class ExpressionFuncExtender
{
private static Expression Compose(this Expression first, Expression second, Func merge)
{
// build parameter map (from parameters of second to parameters of first)
var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
// replace parameters in the second lambda expression with parameters from the first
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
// apply composition of lambda expression bodies to parameters from the first expression
return Expression.Lambda(merge(first.Body, secondBody), first.Parameters);
}
///
/// Combines two given expressions by using the AND semantics.
///
/// The type of the object.
/// The first part of the expression.
/// The second part of the expression.
/// The combined expression.
public static Expression> And(this Expression> first, Expression> second)
{
return first.Compose(second, Expression.AndAlso);
}
///
/// Combines two given expressions by using the OR semantics.
///
/// The type of the object.
/// The first part of the expression.
/// The second part of the expression.
/// The combined expression.
public static Expression> Or(this Expression> first, Expression> second)
{
return first.Compose(second, Expression.OrElse);
}
}
}