This problem has been discussed to an extent in this question: Create Generic Expression from string property name but perhaps I'm missing the answer, or it is subtly different.
I have the following queryable extension method:
public static IQueryable<TSource> OrderByPropertyDescending<TSource>(IQueryable<TSource> source, string propertyName)
{
var sourceType = typeof (TSource);
var parameter = Expression.Parameter(sourceType, "item");
var orderByProperty = Expression.Property(parameter, propertyName);
var orderBy = Expression.Lambda(orderByProperty, new[] { parameter });
return Queryable.OrderByDescending(source, (dynamic) orderBy);
}
For the purposes of this problem let us assume that the queryable source instance has a property called 'Created' which is a type of DateTime. If we define a class that has the property 'Created' on it and then OrderByDescending then the above will work fine. e.g.
var queryable = new List<EntityClassWithCreatedProperty>().AsQueryable();
var result = queryable.OrderByPropertyDescending("Created").ToList();
If we do the same thing but with an interface such as ICreated which has the Created property on it:
public interface ICreated
{
DateTime Created { get; }
}
Then the following also works:
var queryable = new List<ICreated>().AsQueryable();
var result = queryable.OrderByPropertyDescending("Created").ToList();
If however, you have the following interface hierarchy:
public interface ITimestamped : ICreated
{
...
}
Then the following will fail:
var queryable = new List<ITimestamped>().AsQueryable();
var result = queryable.OrderByPropertyDescending("Created").ToList();
With the similar error message to that of the other question: Instance property 'Created' is not defined for type ITimestamped. I'm assuming that I need to find the property on the declaring type of interface (which I can do by crawling the source type) but then what do I do with it? Most attempts I have tried result in the incorrect original source type not being cast-able back to the IQueryable. Do I need to use a ConvertType call somewhere? Thanks.
I would use the other Expression.Property() method that takes a propertyInfo, e.g
public static IQueryable<TSource> OrderByPropertyDescending<TSource>(IQueryable<TSource> source, string propertyName)
{
var sourceType = typeof (TSource);
var parameter = Expression.Parameter(sourceType, "item");
var propertyInfo = FindMyProperty(sourceType, propertyName);
var orderByProperty = Expression.Property(parameter, propertyInfo);
var orderBy = Expression.Lambda(orderByProperty, new[] { parameter });
return Queryable.OrderByDescending(source, (dynamic) orderBy);
}
private static PropertyInfo FindMyProperty(Type type, string propertyName)
{
return type.GetProperty(propertyName);
}
At this point your question has nothing to do with expressions, it's a simple reflection question, and you have to find the correct way to get the properties you want. There are a lot of scenarios here. For your exact one, meaning get property from parent interface, you can do something like:
private static PropertyInfo FindMyProperty(Type type, string propertyName)
{
var result = type.GetProperty(propertyName);
if (result == null)
{
foreach(var iface in type.GetInterfaces())
{
var ifaceProp = FindMyProperty(iface, propertyName);
if (ifaceProp != null)
return ifaceProp;
}
}
return result;
}
DISCLAIMER! This is by no means the best way to get a property from a type, but it should work in your case. You should google around to find an implementation for FindMyProperty that satisfies all your requirements :)