从OrderBy中使用的方法返回表达式

我想编写一个由子类重写的抽象方法,该方法的作用是返回一个表达式,以便随后在LINQ OrderBy() 。 像这样的东西:

注意: Messageinheritance自Notes类, MyModelinheritance自MsgModel

 public class Notes { // abstract definition; using object so that I can (I hope) order by int, string, etc. public abstract Expression<Func> OrderByField(); // ... private string GetOrderByFieldName() { // I am not sure how to write this // This is my problem 2. Please see below for problem 1 :-( var lambda = OrderByField() as LambdaExpression; MemberExpression member = lambda.Body as MemberExpression; PropertyInfo propInfo = member.Member as PropertyInfo; return propInfo.Name; } } public class Message : Notes { // second type parameter is object because I don't know the type // of the orderby field beforehand public override Expression<Func> OrderByField() { return m => m.item_no; } } 

现在,如果我尝试通过这种方式订购:

 var orderedQuery = myQueryable.OrderBy(OrderByField()); 

我收到此错误:

‘无法将类型’System.Int32’强制转换为’System.Object’。 LINQ to Entities仅支持转换EDM原语或枚举类型。

我可以马上说,类型参数对象是问题的原因。 因此,当我将type参数更改为int时,只要我按int字段(例如字段item_no )排序,它就可以正常工作。

Q1。 我怎样才能让它发挥作用? 当然,我可以使用字符串属性OrderByField而不是表达式返回方法和它的顺序,可能是通过为IQueryable编写一些扩展方法(也许使用这个很棒的答案 )。 但是我希望在设置顺序时有更多智能感知。

Q2。 如何从OrderByField()方法返回的表达式中获取列的名称。 显然我尝试过的东西不起作用。 该member始终为null。


编辑:我对方法的类型参数进行了一些更改。 很抱歉没有第一次这样做。

显然, Expression>不等同于Expression> ,因此不能用作Queryable.OrderBy和类似方法所要求的后者的直接替换。

通过Expression.Lambda方法创建非通用LambdaExpression并动态发出对相应Queryable方法的调用,仍然可以在Expression类的帮助下使其工作。

以下是自定义扩展方法中封装的所有内容(我对如何使用字符串通过表达式创建EF顺序的答案的修改版本? ):

 public static partial class QueryableExtensions { public static IOrderedQueryable OrderBy(this IQueryable source, Expression> keySelector) { return source.OrderBy(keySelector, "OrderBy"); } public static IOrderedQueryable OrderByDescending(this IQueryable source, Expression> keySelector) { return source.OrderBy(keySelector, "OrderByDescending"); } public static IOrderedQueryable ThenBy(this IOrderedQueryable source, Expression> keySelector) { return source.OrderBy(keySelector, "ThenBy"); } public static IOrderedQueryable ThenByDescending(this IOrderedQueryable source, Expression> keySelector) { return source.OrderBy(keySelector, "ThenByDescending"); } private static IOrderedQueryable OrderBy(this IQueryable source, Expression> keySelector, string method) { var parameter = keySelector.Parameters[0]; var body = keySelector.Body; if (body.NodeType == ExpressionType.Convert) body = ((UnaryExpression)body).Operand; var selector = Expression.Lambda(body, parameter); var methodCall = Expression.Call( typeof(Queryable), method, new[] { parameter.Type, body.Type }, source.Expression, Expression.Quote(selector)); return (IOrderedQueryable)source.Provider.CreateQuery(methodCall); } } 

这里的一个重要细节是Expression>为表达式返回表达式引入了Expression.Convert ,因此需要从实际的lambda 体中去掉它,这是通过以下代码部分完成的:

 var body = keySelector.Body; if (body.NodeType == ExpressionType.Convert) body = ((UnaryExpression)body).Operand; 

Notes类需要几种generics类型。 第一个是因此你可以从它派生并仍然允许表达式过滤派生类。 第二种是指定您希望用于订购的财产的类型。 例如:

 public abstract class Notes where T : Notes { public abstract Expression> OrderByField(); public string GetOrderByFieldName() { //snip } } public class Message : Notes { public int item_no { get; set; } public override Expression> OrderByField() { return m => m.item_no; } } 

这也应该允许GetOrderByFieldName方法工作。

这是一个(几乎)不使用reflection或表达式的解决方案:它利用了排序LINQ函数在其结果中只有一个generics类型的事实。

1,创建一个接口(只有一个通用参数)和一个实现(带有两个通用参数):

 public interface ISortCrit { string SortFieldName { get; } IOrderedEnumerable MakeOrderBy(IEnumerable source); IOrderedEnumerable MakeOrderByDescending(IEnumerable source); IOrderedEnumerable MakeThenBy(IOrderedEnumerable source); IOrderedEnumerable MakeThenByDescending(IOrderedEnumerable source); IOrderedQueryable MakeOrderBy(IQueryable source); IOrderedQueryable MakeOrderByDescending(IQueryable source); IOrderedQueryable MakeThenBy(IOrderedQueryable source); IOrderedQueryable MakeThenByDescending(IOrderedQueryable source); } public class SortCrit : ISortCrit { private readonly Expression> _sortExpression; private readonly Lazy> _sortDelegate; private readonly Lazy _sortFieldName; public SortCrit(Expression> sortExpression) { _sortExpression = sortExpression; _sortDelegate = new Lazy>(() => sortExpression.Compile()); _sortFieldName = new Lazy(() => ((MemberExpression)sortExpression.Body).Member.Name); } public string SortFieldName => _sortFieldName.Value; public IOrderedEnumerable MakeOrderBy(IEnumerable source) => source.OrderBy(_sortDelegate.Value); public IOrderedEnumerable MakeOrderByDescending(IEnumerable source) => source.OrderByDescending(_sortDelegate.Value); public IOrderedEnumerable MakeThenBy(IOrderedEnumerable source) => source.ThenBy(_sortDelegate.Value); public IOrderedEnumerable MakeThenByDescending(IOrderedEnumerable source) => source.ThenBy(_sortDelegate.Value); public IOrderedQueryable MakeOrderBy(IQueryable source) => source.OrderBy(_sortExpression); public IOrderedQueryable MakeOrderByDescending(IQueryable source) => source.OrderByDescending(_sortExpression); public IOrderedQueryable MakeThenBy(IOrderedQueryable source) => source.ThenBy(_sortExpression); public IOrderedQueryable MakeThenByDescending(IOrderedQueryable source) => source.ThenByDescending(_sortExpression); } 

第二部分会议扩展:

 public static class SortCrit { public static ISortCrit Create(Expression> sortExpression) => new SortCrit(sortExpression); public static IOrderedEnumerable OrderBy(this IEnumerable source, ISortCrit crit) => crit.MakeOrderBy(source); public static IOrderedEnumerable OrderByDescending(this IEnumerable source, ISortCrit crit) => crit.MakeOrderByDescending(source); public static IOrderedEnumerable ThenBy(this IOrderedEnumerable source, ISortCrit crit) => crit.MakeThenBy(source); public static IOrderedEnumerable ThenByDescending(this IOrderedEnumerable source, ISortCrit crit) => crit.MakeThenByDescending(source); public static IOrderedQueryable OrderBy(this IQueryable source, ISortCrit crit) => crit.MakeOrderBy(source); public static IOrderedQueryable OrderByDescending(this IQueryable source, ISortCrit crit) => crit.MakeOrderByDescending(source); public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ISortCrit crit) => crit.MakeThenBy(source); public static IOrderedQueryable ThenByDescending(this IOrderedQueryable source, ISortCrit crit) => crit.MakeThenByDescending(source); } 

用法:

 var messageCrit = SortCrit.Create((Message m) => m.ItemNo); IEnumerable msgs = ...; msgs.OrderBy(messageCrit);