【问题标题】:Creating a lambda expression at runtime在运行时创建 lambda 表达式
【发布时间】:2015-07-15 12:39:07
【问题描述】:

我有一个存储库类,它的 GetAsQueryable 方法定义如下:

public class Repository<TEntity> : IDisposable, IRepository<TEntity> where TEntity : class
{
    internal DbSet<TEntity> _DbSet;

    public virtual IQueryable<TEntity> GetAsQueryable(
         Expression<Func<TEntity, bool>> filter = null,
         Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
         string includeProperties = "")
    {
        IQueryable<TEntity> query = _DbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query);
        }
        else
        {
            return query;
        }
    }
}

在我的调用代码中,我通常会执行以下操作:

IRepository<Tracking> repoTracking = new Repository<Tracking>(context);
IQueryable<Tracking> tracking = repoTracking.GetAsQueryable();
var results = tracking.Where(t => t.Status_Code_Id == 15).ToList();

这很好用;但是现在我希望能够构建在运行时发送到.Where 的 lambda。我尝试构建一个expression tree,如下所示:

IRepository<Tracking> repoTracking = new Repository<Tracking>(context);
IQueryable<Tracking> tracking = repoTracking.GetAsQueryable();
var results = tracking.Where(t => t.Status_Code_Id == 15).ToList();

IRepository<Tracking> repoTracking = new Repository<Tracking>(context);
IQueryable<Tracking> tracking = repoTracking.GetAsQueryable();

ParameterExpression pe = Expression.Parameter(typeof (int), "Status_Code_Id");
LambdaExpression lambda = Expression.Lambda(Expression.Equal(pe, Expression.Constant(15)));
MethodCallExpression whereExpression = Expression.Call(
    typeof(Queryable),
    "Where",
    new Type[] { tracking.ElementType },
    tracking.Expression,
    lambda);

但是,这会产生以下异常:

类型“System.Linq.Queryable”上没有通用方法“Where”与提供的类型参数和参数兼容。如果方法是非泛型的,则不应提供类型参数。

为什么在我的Tracking 实例上找不到Where 方法?

【问题讨论】:

    标签: c# linq lambda


    【解决方案1】:

    如果您想动态构建t =&gt; t.Status_Code_Id == 15,则无需使用Expression 调用Where。只需创建Expression&lt;Func&lt;TEntity, bool&gt;&gt; 并将其传递给Where

    ParameterExpression t = Expression.Parameter(typeof(Tracking), "t");
    Expression statusCode = Expression.Property(t, "Status_Code_Id");
    Expression comparison = Expression.Equal(statusCode, Expression.Constant(15));
    Expression<Func<Tracking, bool>> lambda
        = Expression.Lambda<Func<Tracking, bool>>(comparison, t);
    
    var results = tracking.Where(lambda).ToList();
    

    【讨论】:

    • 我错过了Expression.Parameter(typeof(Tracking), "t"); 部分。能够构建 lambda 以传递给 .Where 方法正是我想要做的! @MarcinJuraszek Dziękuję bardzo!
    【解决方案2】:

    请记住,.Where() 具有通用签名。当您使用 lambda 表达式时,您不必为其提供显式泛型参数,因为编译器可以为您推断类型,但是当您使用反射时,您需要创建一个泛型签名以根据类型调用你正在处理的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多