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;