使用表达式创建扩展方法

时间:2016-10-02 21:50:47

标签: c# linq lambda extension-methods

我试图编写一个通用扩展方法来订购一个IQueryable数据库集合。 (还有更多内容,但这就是我所喜欢的部分。)

我想提供:

  
      
  1. 数据库类(例如客户,雇主)
  2.   
  3. 列的LINQ表达式
  4.   
  5. 列的类型(int,string等)
  6.   

我从一个应该包含信息的类开始,但是我遇到了如何定义和使用表达式的问题。

对于用法,我正在考虑这样的事情,但不确定在哪里为每列提供类型

var sortedList = queryable.MyCustomSortMethod<User>( item =>  new List<SortItem> 
    { item.Column_Name, "ASC" },      //string
    { item.Column_BirthYear "DESC" }, //int
    { item.Column_BirthDate, "ASC" }  //date 
}

然后我有一个类来指定选择器及其方向

public class SortItem<TEntity>
{
    public Expression<Func<T> SortFieldSelector<T>  { get; set; }
    public SortDirectionType SortDirectionType { get; set; }  
    //but how to provide column type
}    

然后扩展方法就像这样

public static IQueryable<TEntity>   MyCustomSortMethod(
    this   IQueryable<TEntity> queryable, 
    List<SortItem<TEntity> selectors)
{

    foreach (var selector in selectors)  {

        if(selector.Direction == "asc")
            queryable = queryable.OrderBy(selector.SortFieldSelector);
        else
            queryable = queryable.OrderByDescending(selector.SortFieldSelector);
    }
    //I need to specify the type of the OrderBy column somehow
    // otherwise compiler errors with "arguments cannot be inferred..." 

    return queryable;

}

我正在探索的兔子洞变得非常丑陋,我确信有一种简单的方法可以做到。

我需要使用扩展方法的事实是一个坚定的要求,但如果它简化了解决方案,其余部分仍然是灵活的。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

您可以这样做:

public class SortItem<TEntity>
{
    public Expression<Func<TEntity, object>> Selector { get; }
    public ListSortDirection Direction { get; }

    public SortItem(Expression<Func<TEntity, object>> selector, ListSortDirection direction)
    {
        Selector = selector;
        Direction = direction;
    }    
}


public static IQueryable<TEntity> MyCustomSortMethod<TEntity>(
    this IQueryable<TEntity> queryable,
    IEnumerable<SortItem<TEntity>> selectors)
{
    foreach (var selector in selectors)
    {
        IOrderedQueryable<TEntity> ordered = queryable as IOrderedQueryable<TEntity>;
        if (ordered == null)
        {
            if (selector.Direction == ListSortDirection.Ascending)
                queryable = queryable.OrderBy(selector.Selector);
            else
                queryable = queryable.OrderByDescending(selector.Selector);
        }
        else
        {
            if (selector.Direction == ListSortDirection.Ascending)
                queryable = ordered.ThenBy(selector.Selector);
            else
                queryable = ordered.ThenByDescending(selector.Selector);
        }
    }
    return queryable;
}

(请注意使用ThenBy代替OrderedBy;如果您每次都使用OrderBy,则只会覆盖之前的订单,而不是完成订单。

免责声明:我没有尝试过,所以我不确定它是否适用于Func<TEntity, object>