using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace Common.LambdaToSQL
{
///
///重写一个表达示树,并将其中引用变量转换成常量
///去除所附加的类信息
///
internal static class PartialEvaluator
{
///
/// Performs evaluation & replacement of independent sub-trees
///
/// The root of the expression tree.
/// A new tree with sub-trees evaluated and replaced.
public static Expression Eval(Expression expression)
{
return Eval(expression, null);
}
///
/// Performs evaluation & replacement of independent sub-trees
///
/// The root of the expression tree.
/// A function that decides whether a given expression node can be part of the local function.
/// A new tree with sub-trees evaluated and replaced.
private static Expression Eval(Expression expression, Func fnCanBeEvaluated)
{
if (fnCanBeEvaluated == null)
fnCanBeEvaluated = PartialEvaluator.CanBeEvaluatedLocally;
return SubtreeEvaluator.Eval(Nominator.Nominate(fnCanBeEvaluated, expression), expression);
}
private static bool CanBeEvaluatedLocally(Expression expression)
{
return expression.NodeType != ExpressionType.Parameter;
}
///
/// Evaluates & replaces sub-trees when first candidate is reached (top-down)
///
private class SubtreeEvaluator : ExpressionVisitor
{
private readonly HashSet _candidates;
private SubtreeEvaluator(HashSet candidates)
{
this._candidates = candidates;
}
internal static Expression Eval(HashSet candidates, Expression exp)
{
return new SubtreeEvaluator(candidates).Visit(exp);
}
protected override Expression Visit(Expression exp)
{
if (exp == null)
{
return null;
}
if (this._candidates.Contains(exp))
{
return this.Evaluate(exp);
}
return base.Visit(exp);
}
private Expression Evaluate(Expression e)
{
Type type = e.Type;
// check for nullable converts & strip them
if (e.NodeType == ExpressionType.Convert)
{
var u = (UnaryExpression)e;
if (TypeHelper.GetNonNullableType(u.Operand.Type) == TypeHelper.GetNonNullableType(type))
{
e = ((UnaryExpression)e).Operand;
}
}
// if we now just have a constant, return it
if (e.NodeType == ExpressionType.Constant)
{
var ce = (ConstantExpression)e;
// if we've lost our nullable typeness add it back
if (e.Type != type && TypeHelper.GetNonNullableType(e.Type) == TypeHelper.GetNonNullableType(type))
{
e = ce = Expression.Constant(ce.Value, type);
}
return e;
}
var me = e as MemberExpression;
if (me != null)
{
// member accesses off of constant's are common, and yet since these partial evals
// are never re-used, using reflection to access the member is faster than compiling
// and invoking a lambda
var ce = me.Expression as ConstantExpression;
if (ce != null)
{
return Expression.Constant(me.Member.GetValue(ce.Value), type);
}
}
if (type.IsValueType)
{
e = Expression.Convert(e, typeof(object));
}
Expression> lambda = Expression.Lambda>(e);
#if NOREFEMIT
Func