5

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
ejwipp
  • 311
  • 6
  • 15

5 Answers5

4

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
jpbochi
  • 4,118
  • 3
  • 29
  • 41
  • This seems like what I was looking. However, I played around with it a little and couldn't get it to compile. When I try to pass func into an OrderBy function the compiler complains. Your method would be slightly cleaner if it would work, but unfortunately I can't devote more time to it right now. – ejwipp Sep 14 '09 at 16:51
  • 1
    When you have time, please tell me what's the compiler error you are seeing. – jpbochi Sep 15 '09 at 04:00
  • I've finally gotten back to this. I think the problem is that in my custom orderBy function, I make a call to ThenBy which doesn't take a Func argument - it requires the lambda expression. – ejwipp Sep 22 '09 at 20:42
  • You can create a `ThenBy` overload that takes a Func then. You should only use lambda expressions when you need to analyze them in some way. If all you need is to execute the expression, then you should use delegates. – jpbochi Sep 23 '09 at 03:38
2

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);
:
ejwipp
  • 311
  • 6
  • 15
1

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.

Community
  • 1
  • 1
Marc Gravell
  • 927,783
  • 236
  • 2,422
  • 2,784
  • That's what I originally had, but I ended up with a ton of "duplicated" code due to the fact I have many fields and need to handle ascending/descending sorts. The answer I posted seems to be working well. – ejwipp Sep 10 '09 at 21:07
0

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

Community
  • 1
  • 1
joaopintocruz
  • 261
  • 3
  • 11
0

I think what you may be looking for is the ability to have a dynamic orderby clause within linq. For some good articles on the topic see

http://blogs.msdn.com/swiss_dpe_team/archive/2008/06/05/composable-linq-to-sql-query-with-dynamic-orderby.aspx

or

http://www.equivalence.co.uk/archives/819

or

http://www.rocksthoughts.com/blog/archive/2008/01/24/linq-to-sql-dynamic-queries.aspx

Anthony Gatlin
  • 4,218
  • 4
  • 33
  • 51