LINQ expression with generic property

2019-02-15 09:24发布

My question is related to this one: linq-expression-with-generic-class-properties

This time I would like to get newly created objects which have the id in common. The id is in fact the foreign key and therefore can have different names.

I came up with the following:

public static IEnumerable<T> GetNew<TId, T>(IQueryable<T> objects, TId id, DateTime date, Expression<Func<T, TId>> idSelector) 
    where T : class, ISyncable<TId>
{
    return objects.Where(o => idSelector(o) == id && o.CreatedDate > date);
}

The method would be called like this:

var modified = GetNew(dbObjects, id, date, entity => entity.PersonId);

Unfortunately I get the error:

'idSelector' is a variable but is used like a method.

The expression passed to the method should do something like that:

objects.Where(o => o.PersonId == id && o.CreatedDate > date);

1条回答
Luminary・发光体
2楼-- · 2019-02-15 10:16

You need to build a new expression representing the condition and pass that to Where:

public static IEnumerable<T> GetNew<TId, T>(IQueryable<T> objects, TId id, DateTime date, Expression<Func<T, TId>> idSelector)
    where T : class, ISyncable<TId>
{
    var paramExpr = Expression.Parameter(typeof(T));
    var idEqExpr = Expression.Equal(Expression.Invoke(idSelector, paramExpr), Expression.Constant(id));
    var createdPropExpr = Expression.Property(paramExpr, "CreatedDate");
    var gtExpr = Expression.GreaterThan(createdPropExpr, Expression.Constant(date));
    var andExpr = Expression.And(idEqExpr, gtExpr);

    var condExpr = Expression.Lambda<Func<T, bool>>(andExpr, paramExpr);

    return objects.Where(condExpr);
}

EDIT: If you know that the idSelector is a property expression, you could extract the referenced property and create a new property expression instead of using Invoke:

var idProperty = (PropertyInfo)((MemberExpression)idSelector.Body).Member;
var idEqExpr = Expression.Equal(Expression.Property(paramExpr, idProperty), Expression.Constant(id));
查看更多
登录 后发表回答