• 扩展IQueryable实现属性名称排序


    基于IEnumerable<T>接口的LINQ to Object扩展函数运行开发人员提供Func<T, TResult>类型的委托实现排序,看一个简单的例子:
    public class Person
    {
        public Person()
            : this(Guid.NewGuid().ToString("N"), DateTime.Now) { }
        public Person(String name, DateTime birth)
        {
            this.Name = name;
            this.Birth = birth;
        }
        public String Name { get; set; }
        public DateTime Birth { get; set; }
    }
     
    IEnumerable<Person> persons = new Person[] { new Person(), new Person(), new Person() };
    IOrderedEnumerable<Person> persons2 = persons.OrderBy(p => p.Name);
    IOrderedEnumerable<Person> persons3 = persons.OrderBy(delegate(Person p) { return p.Name; });
    IOrderedEnumerable<Person> persons4 = persons.OrderBy(p => p.Name, StringComparer.CurrentCultureIgnoreCase);
     
    上面类型中的属性是已知并且可被推导的,如果属性只有一个名称怎么才能够依然可以排序呢?比如下面的写法:
    IOrderedEnumerable<Person> persons = persons.OrderBy("Name");
     
    IQueryable<T>接口可以将查询解析为表达式树,我们可以看到IQueryable<T>的OrderBy、OrderByDescending扩展函数分别相比IEnumerable<T>多了两个接受Expression<Func<T, TResult>>的函数:
    public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector);
    public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, IComparer<TKey> comparer);
    public static IOrderedQueryable<TSource> OrderByDescending<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector);
    public static IOrderedQueryable<TSource> OrderByDescending<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, IComparer<TKey> comparer);
     
    也就说我们可以动态构建Lambda表达式来实现动态调用OrderBy、OrderByDescending函数。看一个例子:
    Type type = typeof(T);
    ParameterExpression arg = Expression.Parameter(type, "p");
    PropertyInfo property = type.GetProperty(propertyName);
    Expression expr = Expression.Property(arg, property);
    Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), property.PropertyType);
    LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
     
    arg就是传递的参数类型,也就是Func<T, TResult>的T类型。通过Expression.Property创建了函数执行体,并定义访问传递参数的某一个属性。最后创建出表达式,等同于p => p.属性。最后找到Queryable静态类型中定义的OrderBy、OrderByDescending函数动态调用就可以实现传递属性名称实现排序。
    public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, String propertyName)
    {
        return InternalOrder<T>(source, propertyName, "OrderBy");
    }
     
    public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, String propertyName)
    {
        return InternalOrder<T>(source, propertyName, "OrderByDescending");
    }
     
    public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, String propertyName)
    {
        return InternalOrder<T>(source, propertyName, "ThenBy");
    }
    public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, String propertyName)
    {
        return InternalOrder<T>(source, propertyName, "ThenByDescending");
    }
     
    private static IOrderedQueryable<T> InternalOrder<T>(IQueryable<T> source, String propertyName, String methodName)
    {
        Type type = typeof(T);
        ParameterExpression arg = Expression.Parameter(type, "p");
        PropertyInfo property = type.GetProperty(propertyName);
        Expression expr = Expression.Property(arg, property);
        Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), property.PropertyType);
        LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
     
        return ((IOrderedQueryable<T>)(typeof(Queryable).GetMethods().Single(
            p => String.Equals(p.Name, methodName, StringComparison.Ordinal)
                && p.IsGenericMethodDefinition
                && p.GetGenericArguments().Length == 2
                && p.GetParameters().Length == 2)
            .MakeGenericMethod(typeof(T), property.PropertyType)
            .Invoke(null, new Object[] { source, lambda })));
    }
     
    IEnumerable<Person> persons = new Person[] { new Person(), new Person(), new Person() };
    IOrderedQueryable<Person> persons2 = persons.AsQueryable().OrderBy("Name");
    IOrderedQueryable<Person> persons3 = persons.AsQueryable().OrderByDescending("Name");
  • 相关阅读:
    Excel文件上传,解析,下载(一 文件上传,使用MultipartFile来实现)
    从svn下载的Mavn项目,到本地后不识别(MyEcplise)
    Tomcat源代码阅读----服务器的启动(2)
    Tomcat源代码阅读----源代码部署(1)
    针对dhtmlX当中的treegrid在java类当中的封装实现的步骤(后台代码)
    Eclipse的maven插件最新地址
    oracle-创建JOB
    简单旋转特效的实现
    Spark SQL 小文件问题处理
    学好Spark/Kafka必须要掌握的Scala技术点(三)高阶函数、方法、柯里化、隐式转换
  • 原文地址:https://www.cnblogs.com/hyl8218/p/2184250.html
Copyright © 2020-2023  润新知