C# 通用函数<;T、 K>;对不同类型的集合进行排序

C# 通用函数<;T、 K>;对不同类型的集合进行排序,c#,.net,asp.net-mvc-3,linq,entity-framework,C#,.net,Asp.net Mvc 3,Linq,Entity Framework,我有许多类型的集合,我想按不同的属性对每个集合进行排序。例如,IEnumerable将按Name和Age属性排序,IEnumerable将按NumberOfEmployees和DepartmentName属性排序。我使用PaginatedList对集合排序后进行分页 public class PaginatedList<T> : List<T> { public PaginatedList(IEnumerable<T> source, Int32 page

我有许多类型的集合,我想按不同的属性对每个集合进行排序。例如,
IEnumerable
将按
Name
Age
属性排序,
IEnumerable
将按
NumberOfEmployees
DepartmentName
属性排序。我使用
PaginatedList
对集合排序后进行分页

public class PaginatedList<T> : List<T>
{
  public PaginatedList(IEnumerable<T> source, Int32 pageIndex, Int32 pageSize , Func<T,Object> orderBy)
  {
    this.AddRange(source.OrderBy(orderBy).Skip((PageIndex - 1) * PageSize).Take(PageSize));
  }
}
公共类分页列表:列表
{
公共分页列表(IEnumerable源、Int32 pageIndex、Int32 pageSize、Func orderBy)
{
this.AddRange(source.OrderBy(OrderBy).Skip((PageIndex-1)*PageSize.Take(PageSize));
}
}
注意第四个参数,它是将传递给OrderBy扩展方法的排序委托

我正在使用一种通用方法来生成第四个元素

public Func<T, Object> SortingFactory<T>(String sortby) 
{
  switch (typeof(T).ToString())
  {
    case "Employee":
      switch(sortby)
      {
        case "Name":
           return new Func<Employee,String>(delegate(Employee e) { return e.Name; });
           break;                            
        case "Age":
           return new Func<Employee,Int32>(delegate(Employee e) { return e.Age; });
           break;
      }
      break;
    case "Department":
      switch(sortby)
      {
        case "NumberOfEmployees":
           return new Func<Department,Int32>(delegate(Department d) { return d.NumberOfEmployees; });
           break;                            
        case "DepartmentName":
           return new Func<Department,String>(delegate(Department d) { return d.DepartmentName; });
           break;
      }
      break;
  }
}
公共函数排序工厂(字符串排序)
{
开关(typeof(T).ToString())
{
案例“雇员”:
开关(sortby)
{
案例“名称”:
返回新函数(委托人(员工e){return e.Name;});
打破
案例“年龄”:
返回新Func(代表(员工e){返回e.年龄;});
打破
}
打破
案例“部门”:
开关(sortby)
{
案例“雇员人数”:
返回新职能(代表(部门d){返回d.NumberOfEmployees;});
打破
案例“部门名称”:
返回新Func(代表(部门d){返回d.DepartmentName;});
打破
}
打破
}
}
但它给了我一个编译错误
无法将类型'System.Func'隐式转换为'System.Func'

我还试图将输出贴标为
Func
,但得到了相同的错误

我犯的错误是什么?这种方法是怎么做的。

说我理解得很好

public class PaginatedList<T> : List<T>
{
  public PaginatedList(IEnumerable<T> source, Int32 pageIndex, Int32 pageSize )
  {
    this.AddRange(GetOrderFor<T>().Skip((PageIndex - 1) * PageSize).Take(PageSize));
  }
}

public static class Helpers
    {

        public static Func<T, object> GetSortExpression<T>(string sortExpressionStr)
        {
            var param = Expression.Parameter(typeof (T), "x");
            var sortExpression = Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(param, sortExpressionStr), typeof(object)), param);
            return sortExpression.Compile();
        }

        public static IOrderedEnumerable<T> GetOrderFor<T>(this IEnumerable<T> list)
        {
            switch (typeof (T).Name)
            {
                case "Employee":
                    return list.OrderBy(GetSortExpression<T>("Name")).ThenBy(GetSortExpression<T>("Age"));
                case "Category":
                    return list.OrderBy(GetSortExpression<T>("Name")).ThenBy(GetSortExpression <T> ("Id"));
            }
            return null;
        }
    }
公共类分页列表:列表
{
公共分页列表(IEnumerable源、Int32 pageIndex、Int32 pageSize)
{
this.AddRange(GetOrderFor().Skip((PageIndex-1)*PageSize.Take(PageSize));
}
}
公共静态类助手
{
公共静态函数GetSortExpression(字符串sortExpressionStr)
{
var param=表达式参数(类型(T),“x”);
var sortExpression=Expression.Lambda(Expression.Convert(Expression.Property(param,sortExpressionStr),typeof(object)),param);
返回sortExpression.Compile();
}
公共静态IOrderedEnumerable GetOrderFor(此IEnumerable列表)
{
开关(类型(T).名称)
{
案例“雇员”:
返回列表。OrderBy(GetSortExpression(“Name”))。然后by(GetSortExpression(“Age”);
案例“类别”:
return list.OrderBy(GetSortExpression(“Name”)).ThenBy(GetSortExpression(“Id”));
}
返回null;
}
}
如果我误解了,我认为简单使用GetSortExpression方法可以帮助您避免错误

case "Employee":
      switch(sortby)
      {
        case "Name":
           return Helpers.GetSortExpression<T>("Name");                           
        case "Age":
           return Helpers.GetSortExpression<T>("Age");
      }
案例“员工”:
开关(sortby)
{
案例“名称”:
return Helpers.GetSortExpression(“Name”);
案例“年龄”:
返回帮助程序。GetSortExpression(“年龄”);
}

代码的主要问题源于尝试在泛型类型之间转换。这里给出的解决方案应该避免这种情况

您应该能够使用
比较器
类。下面是对员工进行排序的示例:

class EmployeeComparer : Comparer<Employee>
{
    string property;

    public EmployeeComparer(string Property)
    {
        this.property = Property;
    }

    public override int Compare(Employee x, Employee y)
    {
        switch (this.property)
        {
            case "Name":
                return Comparer<string>.Default.Compare(x.Name, y.Name);
            case "Age":
                return Comparer<int>.Default.Compare(x.Age, y.Age);
            default:
                return 0;
        }
    }
}
然后,您可以编写一个函数来获取所需类型的比较器:

Comparer<T> GetComparer(string Property)
{
    // Sadly, you cannot switch on a Type
    if (typeof(T) == typeof(Employee))
    {
        return new EmployeeComparer(Property) as Comparer<T>;
    }
    else if (typeof(T) == typeof(Department))
    {
        return new DepartmentComparer(Property) as Comparer<T>;
    }
    else
    {
        return Comparer<T>.Default;
    }
}

嗯。我没有对它进行测试,但是如果你发现了一个bug,请发表评论。

你需要一个更通用的
排序工厂版本,它将返回任何类型的lambda。基本上,这会将字符串转换为可用于排序的强类型表达式:

public Expression<Func<T, To>> SortingFactory<T, To>( String sortby )
{
    // Entity type
    System.Type dataType = typeof( T );

    // Entity - main parameter (x =>
    ParameterExpression rootExp = Expression.Parameter(dataType, "x" );

    // property (x => x.Property
    PropertyInfo pi = dataType.GetProperty( sortby );

    // put together
    Expression expr = Expression.Property( rootExp, pi );
    return Expression.Lambda<Func<T, To>>( expr, rootExp );
}
公共表达式排序工厂(字符串排序)
{
//实体类型
System.Type数据类型=类型(T);
//实体-主参数(x=>
ParameterExpression rootExp=Expression.Parameter(数据类型,“x”);
//属性(x=>x.property
PropertyInfo pi=dataType.GetProperty(sortby);
//拼凑
Expression expr=Expression.Property(rootExp,pi);
返回表达式.Lambda(expr,rootExp);
}
我没有它,但您可能想检查
pi
是否不为null。这还假设传入的字符串是标量属性,而不是实体或集合-这有点棘手

无法将类型“System.Func”隐式转换为“System.Func”
此错误告诉您
Func
不是从
Func
继承的(即使字符串是从对象继承的)。这是一个非常常见的泛型错误!
List
不是从
List
继承的。如果它继承了,您可以避免以下情况:

List<Customer> c = new List<Customer>();
List<object> x = (List<object>) c;
x.Add(x)
//List<object> is-a object, so the statement is valid,
//  but a List<Customer> is not a Customer, breaks the instance referenced by c
// instead of breaking c's instance, you get a runtime exception on line 2 - invalid cast.
List c=新列表();
列表x=(列表)c;
x、 加(x)
//List是一个对象,因此该语句是有效的,
//但是列表不是客户,它破坏了c引用的实例
//不是破坏c的实例,而是在第2行得到一个运行时异常-无效转换。

很多答案都是关于表达的。我觉得这个问题太重了,无法解决

您需要做的是删除/隐藏第二个泛型参数,正如我所做的那样

公共接口IOrderer
{
IOrderedEnumerable ApplyOrderBy(IEnumerable源);
IOR可数应用程序或DerbyDescending(IEnumerable源);
IOrderedEnumerable ApplyThenBy(IOrderedEnumerable源);
IOrderedEnumerable应用程序加密(IOrderedEnumerable源);
} 
公共类排序器:IOrderer
{
私有函数_orderFunc;
公共订购方(Func orderFunc)
{u orderFunc=orderFunc;}
公共IOrderedEnumerable ApplyOrderBy(IEnumerable源)
{返回source.OrderBy(_order
public Expression<Func<T, To>> SortingFactory<T, To>( String sortby )
{
    // Entity type
    System.Type dataType = typeof( T );

    // Entity - main parameter (x =>
    ParameterExpression rootExp = Expression.Parameter(dataType, "x" );

    // property (x => x.Property
    PropertyInfo pi = dataType.GetProperty( sortby );

    // put together
    Expression expr = Expression.Property( rootExp, pi );
    return Expression.Lambda<Func<T, To>>( expr, rootExp );
}
Cannot implicitly convert type 'System.Func<Employee,String>' to 'System.Func<T,object>'
List<Customer> c = new List<Customer>();
List<object> x = (List<object>) c;
x.Add(x)
//List<object> is-a object, so the statement is valid,
//  but a List<Customer> is not a Customer, breaks the instance referenced by c
// instead of breaking c's instance, you get a runtime exception on line 2 - invalid cast.
public interface IOrderer<T>
{
  IOrderedEnumerable<T> ApplyOrderBy(IEnumerable<T> source);
  IOrderedEnumerable<T> ApplyOrderByDescending(IEnumerable<T> source);
  IOrderedEnumerable<T> ApplyThenBy(IOrderedEnumerable<T> source);
  IOrderedEnumerable<T> ApplyThenByDescending(IOrderedEnumerable<T> source);
} 

public class Orderer<T, U> : IOrderer<T>
{
  private Func<T, U> _orderFunc;
  public Orderer(Func<T, U> orderFunc)
  { _orderFunc = orderFunc; }
  public IOrderedEnumerable<T> ApplyOrderBy(IEnumerable<T> source)
  { return source.OrderBy(_orderFunc); }
  public IOrderedEnumerable<T> ApplyOrderByDescending(IEnumerable<T> source)
  { return source.OrderByDescending(_orderFunc); }
  public IOrderedEnumerable<T> ApplyThenBy(IOrderedEnumerable<T> source)
  { return source.ThenBy(_orderFunc); }
  public IOrderedEnumerable<T> ApplyThenByDescending(IOrderedEnumerable<T> source)
  { return source.ThenByDescending(_orderFunc); }
}  
public class PaginatedList<T> : List<T>
{
  public PaginatedList(
    IEnumerable<T> source,
    Int32 pageIndex, Int32 pageSize,
    IOrderer<T> orderer)
  {
    IEnumerable<T> query = orderer.ApplyOrderBy(source)
      .Skip((PageIndex - 1) * PageSize)
      .Take(PageSize)  
    this.AddRange(query);
  }
} 
public class PaginatedList<T> : List<T>
{
  public PaginatedList(
    IEnumerable<T> source,
    Int32 pageIndex, Int32 pageSize,
    List<IOrderer<T>> orderers)
  {
    IEnumerable<T> query = source;

    if (orderers.Any())
    {
      IOrderer<T> firstOrder = orderers.First();
      IOrderedEnumerable<T> orderedQuery = firstOrder.ApplyOrderBy(source);
      foreach(IOrderer<T> nextOrder in orderers.Skip(1))
      {
        orderedQuery = nextOrder.ApplyThenBy(orderedQuery);
      }
      query = orderedQuery;
    }

    this.AddRange(query.Skip((PageIndex - 1) * PageSize).Take(PageSize));
  }
} 
public IOrderer<T> SortingFactory<T>(String sortby)
{
  switch (typeof(T).ToString())
  {
    case "Employee":
       switch(sortby)
       {
         case "Name":
            return new Orderer<Employee, string>(e => e.Name); //hmm, not sure this will work.
            break;