using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace Durkee.Mes.Api.Common
{
///
/// 谓词表达式构建器
///
public static class ExpressionExtensions
{
///
/// 创建一个值恒为 true 的表达式。
///
/// 表达式方法类型
/// 一个值恒为 true 的表达式。
public static Expression> True() { return p => true; }
///
/// 创建一个值恒为 false 的表达式。
///
/// 表达式方法类型
/// 一个值恒为 false 的表达式。
public static Expression> False() { return f => false; }
///
/// 使用 Expression.OrElse 的方式拼接两个 System.Linq.Expression。
///
/// 表达式方法类型
/// 左边的 System.Linq.Expression 。
/// 右边的 System.Linq.Expression。
/// 拼接完成的 System.Linq.Expression。
public static Expression Or(this Expression left, Expression right)
{
return MakeBinary(left, right, Expression.OrElse);
}
///
/// 使用 Expression.AndAlso 的方式拼接两个 System.Linq.Expression。
///
/// 表达式方法类型
/// 左边的 System.Linq.Expression 。
/// 右边的 System.Linq.Expression。
/// 拼接完成的 System.Linq.Expression。
public static Expression And(this Expression left, Expression right)
{
return MakeBinary(left, right, Expression.AndAlso);
}
///
/// 使用自定义的方式拼接两个 System.Linq.Expression。
///
/// 表达式方法类型
/// 左边的 System.Linq.Expression 。
/// 右边的 System.Linq.Expression。
///
/// 拼接完成的 System.Linq.Expression。
private static Expression MakeBinary(this Expression left, Expression right, Func func)
{
return MakeBinary((LambdaExpression)left, right, func) as Expression;
}
///
/// 拼接两个
/// System.Linq.Expression
/// ,两个
/// System.Linq.Expression
/// 的参数必须完全相同。
///
/// 左边的
/// System.Linq.Expression
///
/// 右边的
/// System.Linq.Expression
///
/// 表达式拼接的具体逻辑
/// 拼接完成的
/// System.Linq.Expression
///
private static LambdaExpression MakeBinary(this LambdaExpression left, LambdaExpression right, Func func)
{
var data = Combinate(right.Parameters, left.Parameters).ToArray();
right = ParameterReplace.Replace(right, data) as LambdaExpression;
return Expression.Lambda(func(left.Body, right.Body), left.Parameters.ToArray());
}
///
/// 合并参数
///
///
///
///
///
private static IEnumerable> Combinate(IEnumerable left, IEnumerable right)
{
var a = left.GetEnumerator();
var b = right.GetEnumerator();
while (a.MoveNext() && b.MoveNext())
yield return new KeyValuePair(a.Current, b.Current);
}
}
internal sealed class ParameterReplace : ExpressionVisitor
{
public static Expression Replace(Expression e, IEnumerable> paramList)
{
var item = new ParameterReplace(paramList);
return item.Visit(e);
}
private readonly Dictionary _parameters;
public ParameterReplace(IEnumerable> paramList)
{
_parameters = paramList.ToDictionary(p => p.Key, p => p.Value, new ParameterEquality());
}
protected override Expression VisitParameter(ParameterExpression p)
{
ParameterExpression result;
if (_parameters.TryGetValue(p, out result))
return result;
return base.VisitParameter(p);
}
#region class: ParameterEquality
private class ParameterEquality : IEqualityComparer
{
public bool Equals(ParameterExpression x, ParameterExpression y)
{
if (x == null || y == null)
return false;
return x.Type == y.Type;
}
public int GetHashCode(ParameterExpression obj)
{
if (obj == null)
return 0;
return obj.Type.GetHashCode();
}
}
#endregion
}
}