C# Expression 和 Expression之间的转换

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# Expression 和 Expression之间的转换相关的知识,希望对你有一定的参考价值。

有两个类:

public class User

public int Id get; set;
public string Name get; set;

public class UserDto

public int Id get; set;

如何将:Expression<Func<UserDto, bool>> exp = item => item.Id.Equals(0); 转换成Expression<Func<User, bool>>

你这个都是C# 高级应用了。需要很多的代码呀!你参考一下吧。

namespace System

    public static class LambdaExpressionExtensions
    
        private static Expression Parser(ParameterExpression parameter, Expression expression)
        
            if (expression == null) return null;
            switch (expression.NodeType)
            
                //一元运算符
                case ExpressionType.Negate:
                case ExpressionType.NegateChecked:
                case ExpressionType.Not:
                case ExpressionType.Convert:
                case ExpressionType.ConvertChecked:
                case ExpressionType.ArrayLength:
                case ExpressionType.Quote:
                case ExpressionType.TypeAs:
                    
                        var unary = expression as UnaryExpression;
                        var exp = Parser(parameter, unary.Operand);
                        return Expression.MakeUnary(expression.NodeType, exp, unary.Type, unary.Method);
                    
                //二元运算符
                case ExpressionType.Add:
                case ExpressionType.AddChecked:
                case ExpressionType.Subtract:
                case ExpressionType.SubtractChecked:
                case ExpressionType.Multiply:
                case ExpressionType.MultiplyChecked:
                case ExpressionType.Divide:
                case ExpressionType.Modulo:
                case ExpressionType.And:
                case ExpressionType.AndAlso:
                case ExpressionType.Or:
                case ExpressionType.OrElse:
                case ExpressionType.LessThan:
                case ExpressionType.LessThanOrEqual:
                case ExpressionType.GreaterThan:
                case ExpressionType.GreaterThanOrEqual:
                case ExpressionType.Equal:
                case ExpressionType.NotEqual:
                case ExpressionType.Coalesce:
                case ExpressionType.ArrayIndex:
                case ExpressionType.RightShift:
                case ExpressionType.LeftShift:
                case ExpressionType.ExclusiveOr:
                    
                        var binary = expression as BinaryExpression;
                        var left = Parser(parameter, binary.Left);
                        var right = Parser(parameter, binary.Right);
                        var conversion = Parser(parameter, binary.Conversion);
                        if (binary.NodeType == ExpressionType.Coalesce && binary.Conversion != null)
                        
                            return Expression.Coalesce(left, right, conversion as LambdaExpression);
                        
                        else
                        
                            return Expression.MakeBinary(expression.NodeType, left, right, binary.IsLiftedToNull, binary.Method);
                        
                    
                //其他
                case ExpressionType.Call:
                    
                        var call = expression as MethodCallExpression;
                        List<Expression> arguments = new List<Expression>();
                        foreach (var argument in call.Arguments)
                        
                            arguments.Add(Parser(parameter, argument));
                        
                        var instance = Parser(parameter, call.Object);
                        call = Expression.Call(instance, call.Method, arguments);
                        return call;
                    
                case ExpressionType.Lambda:
                    
                        var Lambda = expression as LambdaExpression;
                        return Parser(parameter, Lambda.Body);
                    
                case ExpressionType.MemberAccess:
                    
                        var memberAccess = expression as MemberExpression;
                        if (memberAccess.Expression == null)
                        
                            memberAccess = Expression.MakeMemberAccess(null, memberAccess.Member);
                        
                        else
                        
                            var exp = Parser(parameter, memberAccess.Expression);
                            var member = exp.Type.GetMember(memberAccess.Member.Name).FirstOrDefault();
                            memberAccess = Expression.MakeMemberAccess(exp, member);
                        
                        return memberAccess;
                    
                case ExpressionType.Parameter:
                    return parameter;
                case ExpressionType.Constant:
                    return expression;
                case ExpressionType.TypeIs:
                    
                        var typeis = expression as TypeBinaryExpression;
                        var exp = Parser(parameter, typeis.Expression);
                        return Expression.TypeIs(exp, typeis.TypeOperand);
                    
                default:
                    throw new Exception(string.Format("Unhandled expression type: '0'", expression.NodeType));
            
        
        public static Expression<Func<TToProperty, bool>> Cast<TInput, TToProperty>(this Expression<Func<TInput, bool>> expression)
        
            var p = Expression.Parameter(typeof(TToProperty), "p");
            var x = Parser(p, expression);
            return Expression.Lambda<Func<TToProperty, bool>>(x, p);
        
    

下面是一个示例:

class Program1

    static int[] array0 = new[]  0, 1 ;
    static void Main(string[] args)
    
        //复杂表达式
        var array1 = new[]  0, 1 ;
        Expression<Func<UserDto, bool>> exp = u =>
            u.Id.Equals(1)
            && u.Name == "张三"
            && u.Id < 10
            && array1.Contains(u.Id)
            && u.Id + 2 < 10
            && (((object)u.Id).ToString() == "1" || u.Name.Contains("三"))
            && Math.Abs(u.Id) == 1
            && Filter(u.Name)
            && true
            ;
        Expression<Func<User, bool>> exp2 = exp.Cast<UserDto, User>();

        //测试数据
        List<User> list = new List<User>()  
            new User Id=0,Name="AAA",
            new User Id=1,Name="张三",
            new User Id=2,Name="李四"
        ;
        var item = list.Where(exp2.Compile()).FirstOrDefault();
        Console.WriteLine(item.Name);
        Console.ReadKey();
    
    public static bool Filter(string name)
    
        return name.Contains("三");
    

应该说常用的筛选条件都是支持的。这里的list由于没有数据库环境就用List<User>模拟的,真实环境你换成list.Where(exp2)就可以了。

参考技术A

转换不了的,还是用接口实际点

public interface IUser
int Idget;set;


public class User:IUser

public int Id  get; set; 
public string Name  get; set;             

public class UserDto:IUser

public int Id  get; set; 

Expression<Func<IUser, bool>> exp = item => item.Id.Equals(0);

追问

你说得对,我也想过这种解决办法,可以解决问题
但是我记得AUTOMAPPER里面好像有这种解决方法!

追答

AutoMapper使用笔记 - dudu - 博客园
http://www.cnblogs.com/dudu/archive/2011/12/16/2284828.html
你是指类似上面博客里的场景3那样的?

追问

不是!

Oracle decode

DECODE()函数,它将输入数值与函数中的参数列表相比较,根据输入值返回一个对应值。函数的参数列表是由若干数值及其对应结果值组成的若干序偶形式。当然如果未能与任何一个实参序偶匹配成功,则函数也有默认的返回值。

语法结构如下:
decode (expression, sch_1, res_1)
decode (expression, sch_1, res_1, sch_2, res_2)
decode (expression, sch_1, res_1, sch_2, res_2, ...., sch_n, res_n)
decode (expression, sch_1, res_1, default)
decode (expression, sch_1, res_1, sch_2, res_2, default)
decode (expression, sch_1, res_1, sch_2, res_2, ...., sch_n, res_n, default)
比较表达式和搜索字,如果匹配,返回结果;如果不匹配,返回default值;如果未定义default值,则返回空值。

以上是关于C# Expression 和 Expression之间的转换的主要内容,如果未能解决你的问题,请参考以下文章

Expression Blend实例中文教程 - 开篇

列表意图表达

Ruby多行三元表达式?

Oracle decode

C# Expression 和 Expression之间的转换

OpenResty 扩展库之——lua-resty-template