Wes Doyle
Wes Doyle

Reputation: 2287

Get property types of generic type for use in expression

I have a method as part of a generic class for use in the context of querying for a collection of objects where a boolean clause in an expression is met, and the result is ordered by some property on the object type.

The current method signature:

Task<T> GetFirstWhere(Expression<Func<T, bool>> whereExp, Expression<Func<T, DateTime>> orderByExp)

With an example implementation:

public async Task<T> GetFirstWhere(Expression<Func<T, bool>> whereExp, Expression<Func<T, DateTime>> orderByExp) {
    return await _entities.Where(whereExp)
        .OrderByDescending(orderByExp)  // I would like to use any valid orderByExp type here
        .FirstOrDefaultAsync();
}

For use in scenarios like:

var foundArticleTag = await _tags.GetFirstWhere(
    tag => tag.Name == articleTag, 
    tag => tag.CreatedOn);

I would like orderByExp function to use any valid type of property on T, rather than explicitly DateTime. I would prefer not to make the type dynamic, so that only valid types of properties on T might be used. I suppose reflection must be required for this, though I am not sure how to enforce the type constraint.

Upvotes: 0

Views: 145

Answers (2)

Guru Stron
Guru Stron

Reputation: 142213

It seems that your method is part of generic type of T, you can make your method generic also (accepting another generic type parameter for ordering expression):

Task<T> GetFirstWhere<TOrder>(
    Expression<Func<T, bool>> whereExp, 
    Expression<Func<T, TOrder>> orderByExp);

That will require adding the generic parameter to the example implementation:

public async Task<T> GetFirstWhere<TOrder>(Expression<Func<T, bool>> whereExp, Expression<Func<T, TOrder>> orderByExp) {
    return await _entities.Where(whereExp)
        .OrderByDescending(orderByExp)  // I would like to use any valid orderByExp type here
        .FirstOrDefaultAsync();
} 

And usage should remain untouched, because the compiler should be able to infer generic TOrder type parameter from the usage.

Upvotes: 3

Gusman
Gusman

Reputation: 15151

You can use as many as generic parameters as you want, so this can be easily extended for a second generic:

public async Task<T> GetFirstWhere<T, O>(Expression<Func<T, bool>> whereExp, Expression<Func<T, O>> orderByExp) {
return await _entities.Where(whereExp)
    .OrderByDescending(orderByExp)
    .FirstOrDefaultAsync();
}

Upvotes: 2

Related Questions