具有泛型属性的LINQ表达式

时间:2013-09-21 13:45:40

标签: c# linq generics lambda

我的问题与此问题有关:linq-expression-with-generic-class-properties

这次我想得到新创建的具有共同id的对象。 id实际上是外键,因此可以有不同的名称。

我想出了以下内容:

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);
}

该方法将被调用如下:

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

不幸的是我收到错误:

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

传递给方法的表达式应该是这样的:

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

1 个答案:

答案 0 :(得分:7)

您需要构建一个表示条件的新表达式并将其传递给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);
}

编辑:如果您知道idSelector是属性表达式,则可以提取引用的属性并创建新的属性表达式,而不是使用Invoke

var idProperty = (PropertyInfo)((MemberExpression)idSelector.Body).Member;
var idEqExpr = Expression.Equal(Expression.Property(paramExpr, idProperty), Expression.Constant(id));