【C#基础】拥抱Lambda(2):表达式树与LINQ
2021-01-17 12:13
                         标签:repo   let   UNC   字段   enum   image   程序   抽象类   推断    一、声明   曾经遇到一个这样的场景:   我就很奇怪,明明a => a.OrderKindCodeId == 16 && a.IsDeleted是Lambda表达式,为什么入参是表示式树呢?一次偶然调试中发现,原来C#支持表达式树的声明像Lambda一样写(当然有一定局限)。   上述报错,是编译器无法推断弱类型是表达式树类型还是Lambda类型,需要指定类型:   不同的原因应该是.Compile()的锅,此处不研究。   换一种方法声明表达式树:   看起来很正常,但运行时compile会报错: System.InvalidOperationException:“从作用域“”引用了“System.String”类型的变量“a”,但该变量未定义”   运算过程出错,因为找不到参数——啥意思?上例的错误其实相当于这样:   二、存储结构   表达式树是有稳定性的,它由一个一个节点挂成一棵树,那怎么修改它?动一棵树,那必然是要遍历的,要递归。   问题又来了,构建一个表达式树如此费劲(不使用lambda表达式下)干嘛要用它——表达式树存在的意义?   三、意义与应用   3 - 1 为什么需要表达式树   表达式树的应用,最后还是要.Compile()成lambda表达式,那为什么不直接用lambda?   ⑴ 调试可见方法如何实现   ⑵ Lambda表达式能转换成表达式树,然后由其他代码处理,从而达到在不同执行环境中执行等价的行为。   Linq To SQL :将源语言(比如C#)生成一个表达式树,其结果作为一个中间格式,再将其转换成目标平台上的本地语言(比如SQL)。   那么这个中间格式直接传lambda表达式行不行?   测试了一下,数据库响应速度特别慢,可能还会发生超时。仅就这个原因,也必须用表达式树了:   看用时:     3 - 2 ExpressionVisitor   上述提及与数据库交互,那就涉及节点值问题(例如节点是一个函数的值,我们希望直接传函数结果而不是传函数),尽量处理得干净一些,这就需要修改(/重构)树,可以使用ExpressionVisitor类。   ExpressionVisitor应该是一个抽象类,程序员按需求继承重写。   这个类主要处理好Parameter和各个节点类型,入口函数应该是Visit(Expression exp),此处仅列出一部分:   应用上例,改动一下:    ExpressionVisitorTest:     先看看要啥效果:    (下载ExpressionVisitor.cs)   例如重写VisitMemberAccess方法:   MemberExpression的属性: MemberExpression CanReduce 能否化简 Expression 值表达式 Member Reflection.RtFieldInfo类型,可处理此处获得真实值 NodeType 节点类型 Type 值类型   处理反射的帮助类:     3 - 3 表达式树的其他作用:   不同类型数字相加,详见 http://mng.bz/9m8i:   但略感到尴尬的是,现在使用的.net 4.6.1已经能支持类型推断了,会推断一个“合适的类型”,也即意味着不用人工去强转类型了:   参考: [0] 深入C# 第三版 [1] https://www.cnblogs.com/FlyEdward/archive/2010/12/06/Linq_ExpressionTree7.html [2] https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/how-to-modify-expression-trees   【C#基础】拥抱Lambda(2):表达式树与LINQ 标签:repo   let   UNC   字段   enum   image   程序   抽象类   推断    原文地址:https://www.cnblogs.com/carmen-019/p/12199029.htmlGetEntities(a => a.OrderKindCodeId == 16 && a.IsDeleted, this.DefaultContext)
protected IEnumerable

Funcstring, string, bool> lambda = (a,b) => a.StartsWith(b);
Expression

static Funcstring, bool> buildlambda(Expression
Expression

e1 = Expression.Lambda(e.Body, e.Parameters); // e1是Expression






        public virtual Expression Visit(Expression exp)
        {
            if (exp == null)
                return exp;
            switch (exp.NodeType)
            {
                case ExpressionType.And: // +
                case ExpressionType.AndAlso: // 并且
                case ExpressionType.LessThan: // 小于
                case ExpressionType.GreaterThan: // 大于
                case ExpressionType.Equal: // 等于
                case ExpressionType.NotEqual: // 不等于
                    return this.VisitBinary((BinaryExpression)exp);
                case ExpressionType.Constant: // 常数
                    return this.VisitConstant((ConstantExpression)exp);
                case ExpressionType.Parameter: // 参数
                    return this.VisitParameter((ParameterExpression)exp);
                case ExpressionType.MemberAccess: //从字段或属性进行读取的运算,如 obj.SampleProperty
                    return this.VisitMemberAccess((MemberExpression)exp);
                case ExpressionType.Call: // 方法调用
                    return this.VisitMethodCall((MethodCallExpression)exp);
                case ExpressionType.Lambda: // Lambda表达式
                    return this.VisitLambda((LambdaExpression)exp);
                default:
                    throw new Exception(string.Format("Unhandled expression type: ‘{0}‘", exp.NodeType));
            }
        }



    public class ExpressionVisitorTest
    {
        public ExpressionVisitorTest() { }
        public Expression Visit(Expression exp)
        {
            if (exp == null)
                return exp;
            switch (exp.NodeType)
            {
                case ExpressionType.Parameter:
                    return VisitParameter((ParameterExpression)exp);
                case ExpressionType.NotEqual:
                    return this.VisitBinary((BinaryExpression)exp);
                case ExpressionType.MemberAccess:
                    return this.VisitMemberAccess((MemberExpression)exp);
                case ExpressionType.Constant:
                    return this.VisitConstant((ConstantExpression)exp);
                default: return exp;
            }
        }
        protected virtual Expression VisitBinary(BinaryExpression b)
        {
            Expression left = this.Visit(b.Left);
            Expression right = this.Visit(b.Right);
            Expression conversion = this.Visit(b.Conversion);
            if (left != b.Left || right != b.Right || conversion != b.Conversion)
            {
                if (b.NodeType == ExpressionType.Coalesce && b.Conversion != null)
                    return Expression.Coalesce(left, right, conversion as LambdaExpression);
                else
                    return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method);
            }
            return b;
        }
        public Expression VisitMemberAccess(MemberExpression exp)
        {
            Expression body = Visit(exp.Expression);
            if (body != exp.Expression)
                return Expression.MakeMemberAccess(exp, exp.Member);
            return exp;
        }
        public Expression VisitParameter(ParameterExpression exp)
        {
            return Parameter;
        }
        protected virtual Expression VisitConstant(ConstantExpression c)
        {
            return c;
        }
        public ParameterExpression Parameter
        {
            get;
            set;
        }
}
   ExpressionVisitor visitor = new ExpressionVisitorInstance();
string testStr = true ? "0" : "123"; 
   Expression


    public class ExpressionVisitorInstance : ExpressionVisitor
    {
        protected override Expression VisitMemberAccess(MemberExpression m)
        {
            Expression expr = base.VisitMemberAccess(m);
            return SimplyMemberAccess(expr);
        }
        private static Expression SimplyMemberAccess(Expression expr)
        {
            MemberExpression me = expr as MemberExpression;
            if (me == null) return expr;
            object target;
            if (me.Expression == null)
                target = null;
            else if (me.Expression is ConstantExpression)
                target = (me.Expression as ConstantExpression).Value;
            else
                return expr;
            return Expression.Constant(me.Member.GetValue(target));
        }
    }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


    public static class ReflectionHelper
    {
        public static object GetValue(this MemberInfo member, object component)
        {
            if (component == null && !member.CanGetFromNull()) return null;
            if (member is PropertyInfo)
                return ((PropertyInfo)member).GetValue(component, null);
            if (member is FieldInfo)
                return ((FieldInfo)member).GetValue(component);
            MethodInfo method = member as MethodInfo;
            if (method != null && typeof(void) != method.ReturnType && method.GetParameters().Length == 0)
            {
                return method.Invoke(component, null);
            }
            return null;
        }
        private static bool CanGetFromNull(this MemberInfo member)
        {
            if (member is PropertyInfo)
                return ((PropertyInfo)member).GetGetMethod().IsStatic;
            else if (member is FieldInfo)
                return ((FieldInfo)member).IsStatic;
            else if (member is MethodBase)
                return ((MethodBase)member).IsStatic;
            else
                return false;
        }
    }
        public static T Add
    int d1 = 1;
    double d2 = 2.1;
    float d4 = 5.5f;
    long d5 = (long)10;
    var d3 = d1+ d2 + d5 + d4; // 存在从int到double的隐式转换
下一篇:C# RSA加密
文章标题:【C#基础】拥抱Lambda(2):表达式树与LINQ
文章链接:http://soscw.com/index.php/essay/43184.html