Question

So i have a method

public IPagedList<MyObject> GetAll<T>(Expression<Func<MyObject, T>>? orderBy, 
    int pageNumber = 1, int pageSize = 10)
{
    return dataContext.MyObjects
      .OrderBy(orderBy.HasValue ? orderBy.Value : <WHAT GOES HERE?>)
      .ToPagedList<MyObject>(pageNumber, pageSize);
}

My goal is to have the orderBy parameter optional, if orderBy is null then default the order to the property MyObject.Id.

I've tried .OrderBy(orderBy.Hasvalue ? orderBy.Value : x => x.Id) but getting this error:

Type of conditional expression cannot be determined because there is no implicit conversion between 'System.Func<MyObject, T>' and 'lambda expression'

What am I doing wrong?

Thanks!

Was it helpful?

Solution

There are a few problems with your code

  • Expression<TDelegate> is a class, so it's nullable already; you can simply test if orderBy == null. Nullable<T> has a generic constraint that T must be a struct, so Expression<Func<MyObject, T>>? won't compile.
  • Next you'll have the problem that because the type T isn't bound inside the method, but x.Id is. In other words, you won't be able to create use the conditional operator to choose between a value of Expression<Func<MyObject, T>> and Expression<Func<MyObject, int>> (assuming that Id is an int) while still maintaining type information to pass to the OrderBy method.

The solution is to use something along these lines:

public IPagedList<MyObject> GetAll<T>(Expression<Func<MyObject, T>> orderBy, 
    int pageNumber = 1, int pageSize = 10)
{
    IQueryable<MyObject> objects = dataContext.MyObjects;
    objects = (orderBy != null) ? objects.OrderBy(orderBy) 
                                : objects.OrderBy(x => x.Id);
    return objects.ToPagedList<MyObject>(pageNumber, pageSize);
}

The conditional operator works in this code because regardless of what you pass to OrderBy the return type will be the same, IQueryable<MyObject>.

Note also that you can't simply pass in a null value for orderBy, because T can't be inferred. You'd have to call it like this:

var results = MyClass.GetAll<int>(null);

Ultimately, you'd probably be better off creating two overloads, one that accepts an orderBy expression, and one that doesn't.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top