C# 如何创建用于运行时排序的表达式树?

C# 如何创建用于运行时排序的表达式树?,c#,entity-framework-4,lambda,C#,Entity Framework 4,Lambda,使用EntityFramework4,我试图实现基于成员名称集合的动态排序。基本上,用户可以选择要排序的字段和排序顺序。我看过表达式树示例,但无法将其拼凑在一起。以下是一些细节: 列名集合: public List<string> sortColumns; sortColumns = new List<string>(); /// Example subset of video fields. The collection will vary. sortColumns

使用EntityFramework4,我试图实现基于成员名称集合的动态排序。基本上,用户可以选择要排序的字段和排序顺序。我看过表达式树示例,但无法将其拼凑在一起。以下是一些细节:

列名集合:

public List<string> sortColumns;
sortColumns = new List<string>();

/// Example subset of video fields.  The collection will vary.
sortColumns.Add("Width");
sortColumns.Add("Height");
sortColumns.Add("Duration");
sortColumns.Add("Title");
公共列表排序列;
sortColumns=新列表();
///视频字段的示例子集。收藏将有所不同。
sortColumns.Add(“宽度”);
sortColumns.添加(“高度”);
sortColumns.Add(“持续时间”);
sortColumns.添加(“标题”);
视频类的定义如下:

public class Video
{
    public string Title { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
    public float Duration { get; set; }
    public string Filename { get; set; }
    public DateTime DateCreated { get; set; }
    .
    .
    .
}
public List<Video> Videos;
公开课视频
{
公共字符串标题{get;set;}
公共整数宽度{get;set;}
公共整数高度{get;set;}
公共浮点持续时间{get;set;}
公共字符串文件名{get;set;}
public DateTime DateCreated{get;set;}
.
.
.
}
公开列表视频;
我想做的是枚举sortColumns集合,以便在运行时构建表达式树。此外,用户可以指定升序排序或降序排序,表达式树应该处理这两种排序

我尝试了VS2008的动态LINQ库,但它在VS2010中似乎不起作用。(我可能做错了什么。)


底线是我需要一个表达式树来根据用户输入动态排序视频集合。任何帮助都将不胜感激。

首先您需要@Slace编写的
OrderBy
扩展方法。这是一段非常棒的代码,也是解决方案中最困难的部分!为了适应您的具体情况,我对其进行了轻微修改:

public static class QueryableExtensions
{
    public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string sortProperty, ListSortDirection sortOrder)
    {
        var type = typeof(T);
        var property = type.GetProperty(sortProperty);
        var parameter = Expression.Parameter(type, "p");
        var propertyAccess = Expression.MakeMemberAccess(parameter, property);
        var orderByExp = Expression.Lambda(propertyAccess, parameter);
        var typeArguments = new Type[] { type, property.PropertyType };
        var methodName = sortOrder == ListSortDirection.Ascending ? "OrderBy" : "OrderByDescending";
        var resultExp = Expression.Call(typeof(Queryable), methodName, typeArguments, source.Expression, Expression.Quote(orderByExp));

        return source.Provider.CreateQuery<T>(resultExp);
    }
}
然后,您应该能够使用如下方法:

// These values are entered by the user
var sortColumns = new List<string> { "Width", "Title", "Height" };
var sortOrder = ListSortDirection.Ascending;

// Print the video list base on the user selection
this.PrintVideoList(sortColumns, sortOrder);
//这些值由用户输入
var sortColumns=新列表{“宽度”、“标题”、“高度”};
var sortOrder=ListSortDirection.升序;
//根据用户选择打印视频列表
这个.PrintVideoList(sortColumns,sortOrder);

正是我所需要的。我注意到,如果使用orderby,它只接受最后一个orderby选择

我将这个方法(然后)添加到我的方法中,似乎效果很好

public static IQueryable<T> ThenBy<T>(this IQueryable<T> source, string sortProperty, ListSortDirection sortOrder)
    {
        var type = typeof(T);
        var property = type.GetTypeInfo().GetDeclaredProperty(sortProperty);
        var parameter = Expression.Parameter(type, "p");
        var propertyAccess = Expression.MakeMemberAccess(parameter, property);
        var orderByExp = Expression.Lambda(propertyAccess, parameter);
        var typeArguments = new Type[] { type, property.PropertyType };
        var methodName = sortOrder == ListSortDirection.Ascending ? "ThenBy" : "ThenByDescending";
        var resultExp = Expression.Call(typeof(Queryable), methodName, typeArguments, source.Expression, Expression.Quote(orderByExp));

        return source.Provider.CreateQuery<T>(resultExp);
    }
public static IQueryable ThenBy(此IQueryable源、字符串sortProperty、ListSortDirection sortOrder)
{
var类型=类型(T);
var property=type.GetTypeInfo().GetDeclaredProperty(sortProperty);
var参数=表达式参数(类型为“p”);
var propertyAccess=Expression.MakeMemberAccess(参数,属性);
var orderByExp=Expression.Lambda(propertyAccess,参数);
var typeArguments=新类型[]{Type,property.PropertyType};
var methodName=sortOrder==ListSortDirection.Ascending?“ThenBy”:“ThenBy Descending”;
var resultextsp=Expression.Call(typeof(Queryable)、methodName、typeArguments、source.Expression、Expression.Quote(orderByExp));
返回source.Provider.CreateQuery(resultExp);
}

@KevinAenmey此代码适用于视频对象列表。在我这方面,我有嵌套类,所以为了访问一些值,我有“Event.Volume.Market\u Leader\u Volume”这样的标签,sortColumn将使用这些标签作为值。您的代码在这里显然不起作用,因为“property”将为null,我在下一行“var propertyAccess=Expression.MakeMemberAccess(parameter,property);”中有一个null异常。有什么办法解决这个问题吗?我知道这是一篇老文章,但您是否能够将其扩展到使用嵌套(导航)属性?
public static IQueryable<T> ThenBy<T>(this IQueryable<T> source, string sortProperty, ListSortDirection sortOrder)
    {
        var type = typeof(T);
        var property = type.GetTypeInfo().GetDeclaredProperty(sortProperty);
        var parameter = Expression.Parameter(type, "p");
        var propertyAccess = Expression.MakeMemberAccess(parameter, property);
        var orderByExp = Expression.Lambda(propertyAccess, parameter);
        var typeArguments = new Type[] { type, property.PropertyType };
        var methodName = sortOrder == ListSortDirection.Ascending ? "ThenBy" : "ThenByDescending";
        var resultExp = Expression.Call(typeof(Queryable), methodName, typeArguments, source.Expression, Expression.Quote(orderByExp));

        return source.Provider.CreateQuery<T>(resultExp);
    }