如何使用表达式树动态地对IQueryable对象进行排序?

时间:2018-10-03 09:58:34

标签: c# .net

目前,我有一个自定义的datagridview,用户可以使用下一个,上一个,第一个和最后一个按钮浏览真实的页面。

在代码的通用部分,我有以下IQueryable对象:IQueryable iqRetVal = iqData;。它的内容由其他形式动态填充,并且可能包含例如用户和下一次公司(因此无法事先知道其中的内容。)。

这是iqData的代码:

IQueryable iqData = null;
public IQueryable Data //this is how iqData is filled.
{
    get { return iqData; }
    set
    {
        iqData = value;
        RefreshDataGridView();
    }
}

现在,我知道用户以前根据2个变量单击过什么:

private SortOrder sortOrder; //The sort order like ascending or descending
private DataGridViewColumn dataGridViewColumn; the column that was sorted on.

这是我的代码给出的错误消息:

  

System.Linq.Queryable类型中没有通用方法OrderByDescending是   与给定的类型参数和参数兼容。没有   如果方法不是通用的,则必须给出typearguments。

代码本身:

try
{
    if (dataGridViewColumn != null)
    {
        var propName = dataGridViewColumn.DataPropertyName;
        ParameterExpression param = null;

        foreach (var item in iqRetVal)
        {
            if (item != null)
            {
                param = Expression.Parameter(item.GetType(), string.Empty);
                break;
            }
        }
        MemberExpression property = Expression.PropertyOrField(param, propName);
        LambdaExpression sort = Expression.Lambda(property, param);

        if (sortOrder == SortOrder.Descending)
        {
            iqRetVal = iqRetVal.Provider.CreateQuery(Expression.Call(typeof(Queryable), "OrderBy", new Type[] { iqRetVal.ElementType }, iqRetVal.Expression, Expression.Quote(sort)));
        }
        else
        {
            iqRetVal = iqRetVal.Provider.CreateQuery(Expression.Call(typeof(Queryable), "OrderByDescending", new Type[] { iqRetVal.ElementType }, iqRetVal.Expression, Expression.Quote(sort)));
        }

    }
    else { }
}
catch(Exception ex)
{
    MessageBox.Show(ex.Message);
    System.Diagnostics.Debug.WriteLine(ex.Message);
}

我到底缺少什么来使我的代码正常工作?因为我已经搜索了很长时间,但似乎大多数答案都无法提供我想要的答案。

1 个答案:

答案 0 :(得分:1)

导致问题的方法调用是这样的:

Expression.Call(typeof(Queryable), "OrderBy", new Type[] { iqRetVal.ElementType }, iqRetVal.Expression, Expression.Quote(sort));

documentation for this overload of CreateQuery,我们可以看到第一个参数是包含静态方法的类型,第二个是方法名称,第三个是该方法所需的通用参数,后续项是方法的参数。

OrderBy上确实存在Queryable方法,因此我们的前两个参数很好。如果我们look at this method,那么我们看到它有两个通用参数:OrderBy<TSource,TKey>。目前,我们只传递一种类型。这表明出现错误消息,指出类型参数不正确。

因此,我们的第一种类型是我们正确获取为iqRetVal.ElementType的Queryable的类型。第二个是我们的排序选择器返回的键的类型。可以使用sort.ReturnType找到。

因此这将使方法调用看起来像这样:

Expression.Call(typeof(Queryable), "OrderBy", new Type[] { iqRetVal.ElementType, sort.ReturnType }, iqRetVal.Expression, Expression.Quote(sort))