• Expression表达式目录树动态拼接 反射获取泛型方法


        class TestOne
        {
    
            public String[] arr = { "1", "2", "3" };
    
            public class Student
            {
                public int Id { get; set; }
                public string Name { get; set; }
                public String Code { get; set; }
            }
    
            public Expression<Func<Student, bool>> Fun1()
            {
    
                Expression<Func<Student, bool>> customExpression = s => arr.Contains(s.Code);
    
                return customExpression;
    
            }       
    
        }
    

      上面我贴出了源码,如果要用 Expression动态拼接出  Expression<Func<Student, bool>> customExpression = s => arr.Contains(s.Code) ,该怎么弄。

    这里包含很多东西,访问类Student的属性Code,访问类TestOne的字段arr,然后就是arr调用Contains方法。

      选从简单的开始,选动态拼装 s.Code 直接上代码

                ParameterExpression parameterExpression = Expression.Parameter(typeof(Student), "s");
                MethodInfo codeMethod = typeof(Student).GetProperty("Code").GetMethod;
                MemberExpression memberExpression = Expression.Property(parameterExpression, codeMethod);
    

       s.Code 已经准备好了,然后开始拼装arr.Contains(),这里我们很容易会误以为Contains这个方法是String数组所拥有的方法。其实是错误的,直接F12查看方法定义,

    发现它是在静态类Enumerable里写的一个参数为IEnumerable<TSource> 的泛型扩展方法。所以

                MethodInfo[] methods = typeof(Enumerable).GetMethods();
                MethodInfo method1 = methods.FirstOrDefault(e => e.Name == "Contains" && e.GetParameters().Length == 2);
                //MethodInfo method1 = typeof(Enumerable).GetMethod("Contains", new Type[] { typeof(IEnumerable<>), null });
                MethodInfo method2 = method1.MakeGenericMethod(typeof(String));
    

    其中method1的获取还大费周折了一番。刚开始我直接用GetMethod方法直接获取到所需要的Contains方法的MethodInfo对象,但是在填写类型Type数组时,你会发现,第二个参数的类型你不知道怎么填写,因为它是一个泛型参数,所以你不知道它是什么类型(上面代码被注释的那一行代码)。为此,我上网这种搜,研究了一晚上,也没有破解。所以就采用第二种方案。用GetMethods获取所有MethodInfo对象,然后再筛选。

    完成了关键步骤,就好办了,贴出全部代码

            public Expression<Func<Student, bool>> Fun2()
            {
    
                ParameterExpression parameterExpression = Expression.Parameter(typeof(Student), "s");
                MethodInfo codeMethod = typeof(Student).GetProperty("Code").GetMethod;
                MemberExpression memberExpression = Expression.Property(parameterExpression, codeMethod);
    
                FieldInfo filed = typeof(TestOne).GetField("arr");
                MemberExpression filedExpression = Expression.Field(Expression.Constant(this, typeof(TestOne)), filed);
    
    
                MethodInfo[] methods = typeof(Enumerable).GetMethods();
                MethodInfo method1 = methods.FirstOrDefault(e => e.Name == "Contains" && e.GetParameters().Length == 2);
                //MethodInfo method1 = typeof(Enumerable).GetMethod("Contains", new Type[] { typeof(IEnumerable<>), null });
                MethodInfo method2 = method1.MakeGenericMethod(typeof(String));         
    
                MethodCallExpression callExpression = Expression.Call(null, method2, new Expression[]
                {
                    filedExpression,
                    memberExpression,
                });
    
                Expression<Func<Student, bool>> customExpression = Expression.Lambda<Func<Student, bool>>
                    (callExpression, new ParameterExpression[] { parameterExpression });
    
                return customExpression;
            }
    

      

    对于我上面提到的一个问题就是 用GetMethod方法 直接获取到Contains方法的MethodInfo对象。这个是从理论上就实现不了(因为是泛型,再没有调用之前是不知道类型的),还是说微软框架就没有提供这种直接获取到泛型参数的MethodInfo对象的实现。有了解的朋友欢迎留言指点讨论。

  • 相关阅读:
    80端口被NT kernel & System 占用pid 4的解决方法 80端口被占用
    Linux:linux输入输出重定向、管道命令grep/wc、linux进程管理ps、pstree、kill命令、linux防火墙命令firewall-cmd、防火墙开启关闭端口号
    Linux:Linu文件权限管理、文件权限修改chmod、修改属主属组chown、特殊权限SUID、SGID、Sticky、umask
    [Java]获取图片高和宽
    [Java]获取Window界面的标题栏的高度大小
    [算法 笔记]字符串表达式计算(简易版)
    [算法 笔记]大数相乘(续)
    [算法 笔记]2014年去哪儿网 开发笔试(续)第一题BUG修正
    [算法 笔记]堆排序(续)
    [算法 笔记]用小范围随机函数编写大范围随机函数
  • 原文地址:https://www.cnblogs.com/xiaoZhang521/p/11374258.html
Copyright © 2020-2023  润新知