关于c#:用反射可以做到这一点吗?

Is it possible to do this with reflection?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Dynamic LINQ OrderBy

我有一个自定义排序选项列表,这些选项通过客户端网格控件(如果您想知道,可以使用Kendoui网格)传递给服务器。这些排序选项具有作为字符串排序的属性。我编写了一个switch方法,它将检查sort对象的值并应用适当的linq。

1
2
3
4
5
6
7
8
9
10
11
12
    private IQueryable<Report> SortReports(IQueryable<Report> reports, KendoSort sort)
    {
        switch (sort.Field)
        {
            case"name":
                return sort.Dir =="asc" ? reports.OrderBy(x => x.Name) : reports.OrderByDescending(x => x.Name);
            case"description":
                return sort.Dir =="asc" ? reports.OrderBy(x => x.Description) : reports.OrderByDescending(x => x.Description);
            default:
                return sort.Dir =="asc" ? reports.OrderBy(x => x.Id) : reports.OrderByDescending(x => x.Id);
        }
    }

这很管用,但看起来很难看。我如何利用反射来实现这一点,这样就不必为每种类型的实体编写自定义函数了?如果我能有一个单独的函数,不管实体是什么,都能做到这一点,那就太好了。


您可以使用动态LINQ。这是顾司各特写的一篇关于它的文章。


下面应该创建动态需要的排序函数。

1
2
3
4
5
6
7
8
ParameterExpression pe = Expression.Parameter(typeof(Report),"x");
LambdaExpression le = Expression.Lambda(
    Expression.PropertyOrField(pe, sort.Field),
    new List<ParameterExpression>() {pe});

var leCompiled = (Func<Report, string>)le.Compile();                

return sort.Dir =="asc" ? reports.OrderBy(leCompiled) : reports.OrderByDescending(leCompiled);

它以x=>x.reportproperty的形式创建了一个func委托,其中reportproperty是sort.field的值。


使用反射,其中kendosort.property是返回排序所需值的报表属性的propertyinfo。

1
2
3
4
private IQueryable<Report> SortReports(IQueryable<Report> reports, KendoSort sort)
{
    return sort.Dir =="asc" ? reports.OrderBy(x => sort.Property.GetValue(x)) : reports.OrderByDescending(x => sort.Property.GetValue(x));
}

但是,反射速度相对较慢。其他解决方案可能更好。


MarcGravell有一个叫做FastMember的伟大的小图书馆。您可以这样使用它:

1
2
3
4
5
6
7
private IQueryable<Report> SortReports(IQueryable<Report> reports,KendoSort sort)
{
    var accessor = TypeAccessor.Create(typeof(Report));
    return sort.Dir =="asc" ?
        reports.OrderBy(x => accessor[x,sort.Field]) :
        reports.OrderByDescending(x => accessor[x,sort.Field]));
}