Problem with Generic Linq OrderBy function

2019-01-26 14:40发布

I saw the following function in a posting which allows one to order data using a generic expression:

public static IOrderedQueryable<T> OrderBy<T, TKey>(
  this IQueryable<T> source, Expression<Func<T, TKey>> func, bool isDescending) {
  return isDescending ? source.OrderByDescending(func) : source.OrderBy(func);
}

When I try to use this function I get an error saying "The type or namespace name "TKey' could not be found (are you missing a using directive or an assembly reference?)". I'm doing something dumb here but I can't figure it out.

Edit:

After doing a bit more research, I think my problem is in building the Expression that I pass into it. Is it possible to build an expression that can contain different types? Let's say my dataset has a string, an int, and a bool and I want to use the generic function above to sort by any of the items. How do I do this?

I have this working now:

if (IsString)
{
   Expression<Func<T, string>> expString = ...;
   // call orderBy with expString
}
else if (IsInt)
{
   Expression<Func<T, int>> expInt;
   // call orderBy w/ expInt
}
:

I want something like:

Expression<Func<T, {something generic!}>> exp;
if (IsString)
    exp = ...;
else if (IsInt)
    exp = ...;
:
// call orderBy with exp

标签: c# linq lambda
5条回答
成全新的幸福
2楼-- · 2019-01-26 14:58

My goal in this was to eliminate a lot of repetitious code. In addition to handling the ascending/descending my "OrderBy" function handles some other common logic has well. Assuming the function definition in the original posting, one can simply do this:

if ( {need to sort by integer})
    query = OrderBy(objectT, a => a.myIntegerField, asc);
else if ( {need to sort by string})
    query = OrderBy(objectT, a=> a.myStringField, asc);
:
查看更多
Juvenile、少年°
3楼-- · 2019-01-26 15:01

The expression can only have one type; my preferred answer here would be something like:

IQueryable<T> query = ...
if({case 1}) {
    query = query.OrderBy(x=>x.SomeValue);
} else if({case 2}) {
    query = query.OrderBy(x=>x.SomeOtherValue);
} ...

However, if you want to do something more flexible, you'd probably need to get into custom Expression writing; something more like this.

查看更多
4楼-- · 2019-01-26 15:12

Take a look at this answer

My generic handler for sorting is:

  • "dgvProcessList" is my dataGridView
  • "Process" is my object binded to it
  • "e" is my DataGridViewCellMouseEventArgs

                PropertyInfo column = (new Process()).GetType().GetProperties().Where(x => x.Name == dgvProcessList.Columns[e.ColumnIndex].Name).First();
            if (isSortedASC == true)
                dgvProcessList.DataSource = ((List<Process>)dgvProcessList.DataSource).OrderByDescending(x => column.GetValue(x, null)).ToList();
            else
                dgvProcessList.DataSource = ((List<Process>)dgvProcessList.DataSource).OrderBy(x => column.GetValue(x, null)).ToList();
    
            isSortedASC = !isSortedASC;
            dgvProcessList.ClearSelection();
    

Cheers

查看更多
相关推荐>>
6楼-- · 2019-01-26 15:16

One quick observation: You don't really need to use a lambda expression (Expression<Func<T,TKey>>). A simple delegate (Func<T,TKey>) is fine.

That said, I think the answer you might be looking for is this:

Func<T,IComparable> func = null;
if (IsString)
    func = (T a) => a.SomeStringValue;
else if (IsInt)
    func = (T a) => a.SomeIntValue;
// call orderBy with exp
查看更多
登录 后发表回答