Expression 表达式目录树

目录

一、Expression概念

二、Expression基础调用

1、简略版

2、完整版

三、Expression应用 -- 复制相同类

方法一:硬编码

方法二:反射

方法三:序列化

方法四:表达式目录树_Method

方法五:表达式目录树_Class -- 推荐(最快)

四、ExpressionVisitor解析

五、ExpressionVisitor合并


一、Expression概念

表达式目录树,只能一行,不可用花括号
目的: 将C#语句转化成SQL语句,隔离数据库,让开发人员无需为不同的数据库而发愁
ExpressionVisitor 递归获取每个表达式的值,然后在进行拼装,
               即:先拆一遍,再每个元素拼装一遍,整个过程是递归两遍
               Expression解析表达式,是用Expression的的一部分
               Expression链接表达式,是用Expression的的一部分
               两者各是整个过程的一半,谨慎合并使用

二、Expression基础调用

前期准备:

public static int GetSum(int x)
{
    return x + 1;
}

1、简略版

代码编写:

//传入一行的Lambda表达式
Expression<Func<int, bool>> exp = (x) => (x + GetSum(x)).Equals(7);
//表达式调用
Console.WriteLine(exp.Compile().Invoke(3));

2、完整版

代码编写:

//入参x配置
ParameterExpression _x = Expression.Parameter(typeof(int), "x");

//GetSum 获取
MethodInfo getSum = typeof(Program).GetMethod("GetSum");
//GetSum(x) 配置
MethodCallExpression getSum_x = Expression.Call(null, getSum, _x);
//(x + GetSum(x)) 配置
BinaryExpression callLeft = Expression.Add(_x, getSum_x);

//Equals方法配置
MethodInfo equals = typeof(Int32).GetMethod("Equals", new[] { typeof(Int32) });
//7 配置
ConstantExpression _7 = Expression.Constant(7, typeof(int));
//(x + GetSum(x)).Equals(7) 配置
MethodCallExpression callAll = Expression.Call(callLeft, equals, _7);

//整体组合
Expression<Func<int, bool>> exp1 =
    Expression.Lambda<Func<int, bool>>(callAll,
        new ParameterExpression[1] { _x });

//调用
Console.WriteLine(exp1.Compile()(3));

//--------------------------------------------------------------------------------------------------------------------------------------- 

如何快速获取完整版:通过ILSpy反编译简单语句获取。

                                        若无法得到,可参考 http://t.csdn.cn/hsuVq

注:在ILSpy中 (MethodInfo)MethodBase.GetMethodFromHandle(RuntimeMethodHandle) 要进行手动配置

//GetSum 获取
MethodInfo getSum1 = typeof(Program).GetMethod("GetSum");
// (MethodInfo)MethodBase.GetMethodFromHandle(RuntimeMethodHandle)

//Equals方法配置
MethodInfo equals1 = typeof(Int32).GetMethod("Equals", new[] { typeof(Int32) });
//(MethodInfo)MethodBase.GetMethodFromHandle(RuntimeMethodHandle)

三、Expression应用 -- 复制相同类

前期准备:

People Tom = new People { _id = 1, _name = "Tom", _age = 18 };

class People
{
    public int _id;
    public string _name;
    public int _age;
}
class NewPeople
{
    public int _id;
    public string _name;
    public int _age;
} 

方法一:硬编码

代码编写:

NewPeople TomNew_1 = new NewPeople
{
    _id = Tom._id,
    _name = Tom._name,
    _age = Tom._age
};

方法二:反射

代码编写:

NewPeople TomNew_2 = Copy(Tom);

public static NewPeople Copy(People Tom)
{
    NewPeople TomNew = Activator.CreateInstance<NewPeople>();
    foreach (var item in Tom.GetType().GetFields())
    {
        TomNew.GetType().GetField(item.Name).SetValue(TomNew, item.GetValue(Tom));
    }
    return TomNew;
}

方法三:序列化

代码编写:

var TomNew_3 = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(Tom));

方法四:表达式目录树_Method

代码解析:转换代码写成Expression形式,保存至字典中,二次调用时,通过key直接调用Expression表达式

代码编写:

NewPeople TomNew_4 = Trans<People, NewPeople>(Tom);

private static Dictionary<string, object> _Dic = new Dictionary<string, object>();

public static TOut Trans<TIn, TOut>(TIn Tom)
{
    string key = string.Format($"funckey_{typeof(TIn).FullName}_{typeof(TOut).FullName}");
    if (!_Dic.ContainsKey(key)) //若没有key
    {
        //入参
        ParameterExpression param = Expression.Parameter(typeof(TIn), "x");
        //成员列表
        List<MemberBinding> memberBindings = new List<MemberBinding>();
        //遍历字段
        foreach (FieldInfo item in typeof(TOut).GetFields())
        {
            var field = Expression.Field(param, typeof(TIn).GetField(item.Name));
            MemberBinding memberBinding = Expression.Bind(item, field);
            memberBindings.Add(memberBinding);
        }

        MemberInitExpression memberInit = Expression.MemberInit(
                Expression.New(typeof(NewPeople)),
                memberBindings.ToArray());

        Expression<Func<TIn, TOut>> ELambda = Expression.Lambda<Func<TIn, TOut>>(memberInit,
                                                                             new ParameterExpression[1] { param });

        _Dic[key] = ELambda.Compile();
    }
    return ((Func<TIn, TOut>)_Dic[key]).Invoke(Tom);

方法五:表达式目录树_Class -- 推荐(最快)

代码解析:初次调用时,转换代码写成Expression形式,二次调用时,通过类名直接获取Expression表达式

注:静态构造方法的使用

代码编写:

var TomNew_5 = ExpressionTrans<People, NewPeople>.Trans(Tom);

class ExpressionTrans<TIn, TOut>
{
    private static Func<TIn, TOut> _Fun = null;
    static ExpressionTrans()
    {
        //入参
        ParameterExpression param = Expression.Parameter(typeof(TIn), "x");
        //成员列表
        List<MemberBinding> memberBindings = new List<MemberBinding>();
        //遍历字段
        foreach (FieldInfo item in typeof(TOut).GetFields())
        {
            var field = Expression.Field(param, typeof(TIn).GetField(item.Name));
            MemberBinding memberBinding = Expression.Bind(item, field);
            memberBindings.Add(memberBinding);
        }

        MemberInitExpression memberInit = Expression.MemberInit(
                Expression.New(typeof(NewPeople)),
                memberBindings.ToArray());

        Expression<Func<TIn, TOut>> ELambda = Expression.Lambda<Func<TIn, TOut>>(memberInit,
                                                                              new ParameterExpression[1] { param });
        _Fun = ELambda.Compile();
    }
    public static TOut Trans(TIn Tom)
    {
        return _Fun.Invoke(Tom);
    }
}

四、ExpressionVisitor解析

前期准备:

class People
{
    public int Id { get; set; }
    public int Age { get; set; } 
}
//------------------------------------------------------------------
/// <summary>
/// 表达式条件建筑类
/// </summary>
class ConditionBuilderVisitor : ExpressionVisitor
{
    /// <summary>
    /// 栈:先进后出
    /// </summary>
    private Stack<string> _stack = new Stack<string>();

    /// <summary>
    /// 栈转字符串
    /// </summary>
    public string Condition()
    {
        string condition = string.Concat(this._stack.ToArray());
        this._stack.Clear();
        return condition;
    }

    /// <summary>
    /// 二元表达式压入
    /// </summary>
    protected override Expression VisitBinary(BinaryExpression node)
    {
        if (node == null) throw new ArgumentException("BinaryExpression");

        this._stack.Push(")");
        base.Visit(node.Right); //解析右边
        this._stack.Push(" " + node.NodeType.ToSqlOperator() + " ");
        base.Visit(node.Left); //解析左边
        this._stack.Push("(");

        return node;
    }
    /// <summary>
    /// 元素压入
    /// </summary>
    protected override Expression VisitMember(MemberExpression node)
    {
        if (node == null) throw new ArgumentException("MemberExpression");

        this._stack.Push($"[{node.Member.Name}]");
        return node;
    }

    /// <summary>
    /// 常数压入
    /// </summary>
    protected override Expression VisitConstant(ConstantExpression node)
    {
        if (node == null) throw new ArgumentException("ConstantExpression");

        //压入常数
        this._stack.Push($"'{node.Value.ToString()}'");
        return node;
    }
}

//---------------------------添加扩展方法----------------------------------
static class ExpressionVisitorExtend
{
    /// <summary>
    /// 类型转字符
    /// </summary>
    internal static string ToSqlOperator(this ExpressionType type)
    {
        switch (type)
        {
            case ExpressionType.Add:
                return "+";
            case ExpressionType.Subtract:
                return "-";
            case ExpressionType.Multiply:
                return "*";
            case ExpressionType.Divide:
                return "/";
            case ExpressionType.AndAlso:
            case ExpressionType.And:
                return "AND";
            case ExpressionType.OrElse:
            case ExpressionType.Or:
                return "OR";
            case ExpressionType.Not:
                return "NOT";
            case ExpressionType.NotEqual:
                return "<>";
            case ExpressionType.GreaterThan:
                return ">";
            case ExpressionType.GreaterThanOrEqual:
                return ">=";
            case ExpressionType.LessThan:
                return "<";
            case ExpressionType.LessThanOrEqual:
                return "<=";
            case ExpressionType.Equal:
                return "=";
            default:
                throw new Exception("不支持该方法");
        }
    }

代码编写:

internal class Program
{
    static void Main(string[] args)
    {
        Expression<Func<People, int>> exp = (x) => x._Id + 5 + 4 - 6;
        ConditionBuilderVisitor conditional = new ConditionBuilderVisitor();
        conditional.Visit(exp);
        string result = conditional.Condition();
        Console.WriteLine(result); //结果显示:((([_Id] + '5') + '4') - '6')
    }
}

五、ExpressionVisitor合并

前期准备:

class People
{
    public int _Id { set; get; }
    public int _Age { set; get; }
}

//-------------------------------- 入参统一 ------------------------------
internal class NewExpressionVisitor : ExpressionVisitor
{
    public ParameterExpression _NewParameter { get; private set; }

    public NewExpressionVisitor(ParameterExpression newParameter)
    {
        _NewParameter = newParameter;
    }

    /// <summary>
    /// 入参设定
    /// </summary>
    protected override Expression VisitParameter(ParameterExpression node)
    {
        return this._NewParameter;
    }
}

//-----------------------------------扩展方法-----------------------------
static class ExpressionVisitorExtend
{
        /// <summary>
        /// 与和或的父方法
        /// </summary>
    private static Expression<Func<T, bool>> AndOr<T>(this Expression<Func<T, bool>> exp1,
                                                          Expression<Func<T, bool>> exp2,
                                                          Func<Expression, Expression, BinaryExpression> func)
        {
            ParameterExpression newParameter = Expression.Parameter(typeof(T), "x");
            NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter);

            var left = visitor.Visit(exp1.Body);
            var right = visitor.Visit(exp2.Body);
            var body = func(left, right);

            return Expression.Lambda<Func<T, bool>>(body, newParameter);
        }
        /// <summary>
        /// 两个条件 -- 与运算
        /// </summary>
    internal static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> exp1,
                                                          Expression<Func<T, bool>> exp2)
        {
            return AndOr(exp1, exp2, Expression.And);
        }
        /// <summary>
        /// 两个条件 -- 或运算
        /// </summary>
    internal static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> exp1,
                                                          Expression<Func<T, bool>> exp2)
        {
            return AndOr(exp1, exp2, Expression.Or);
        }
        /// <summary>
        /// 两个条件 -- 非运算
        /// </summary>
    internal static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> exp)
        {
            var parameter = exp.Parameters[0];
            var body = Expression.Not(exp.Body);

            return Expression.Lambda<Func<T, bool>>(body, parameter);
        }

}

代码编写:

internal class Program
{
    static void Main(string[] args)
    {
        List<People> peoples = new List<People>()
        {
            new People(){ _Id = 1000,_Age = 20},
            new People(){ _Id = 500,_Age = 21},
            new People(){ _Id = 640,_Age = 25},
            new People(){ _Id = 2300,_Age = 28}
        };

        Expression<Func<People, bool>> exp1 = (x) => x._Age > 18;
        Expression<Func<People, bool>> exp2 = (y) => y._Id > 700;
        //获取表达式
        
        var result = exp1.And(exp2); 
        //调用获取结果
        var list = peoples.Where(result.Compile()).ToList();

        //result结果:x => ((x._Age > 18) And (x._Id > 700))
        Console.WriteLine(result);

    }
}

如有错误,烦请批评指正

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值