组合表达式树

时间:2016-04-20 07:03:39

标签: c# linq expression iqueryable func

我有以下表达式:

public Expression<Func<T, bool>> UserAccessCheckExpression<T>(int userId) where T : class
{
    return x => (IsAdmin || userId == CurrentUserId || userId == 0);
}

然后我想将此过滤器应用于几个集合(IQueryable),如下所示:

return tasks
  .Where(t => t.TaskUsers
     .Any(x => UserAccessCheckExpression<TaskUser>(x.User) && x.SomeBool == true));

执行此操作时出现以下错误:

  

错误40无法将类型System.Linq.Expressions.Expression<System.Func<TaskUser,bool>>隐式转换为bool

我无法使用接口继承的解决方法(比如TaskUser继承了带有int UserId属性的接口(其中T:IHasUserId)),因为我想要组合逻辑。

2 个答案:

答案 0 :(得分:2)

问题是,当UserAccessCheckExpression()方法期待Expression时,您的Any()方法返回boolean

现在,您可以通过编译Expression并调用方法(使用UserAccessCheckExpression<TaskUser>(x.User).Compile().Invoke(x.User))来获取编译的代码,但这显然会在运行时失败,因为Linq-to-实体无法将您的Any()翻译为商店查询,因为它不再包含Expression

LinqKit旨在使用自己的Invoke扩展方法来解决此问题,该方法允许您的代码编译,同时确保您的Expression将被替换回其原始格式名为AsExpandable()的扩展方法,用于扩展实体集。

试试这个:

using LinqKit.Extensions;

return tasks
      .AsExpandable()
      .Where(t => t.TaskUsers.Any(
                       x => UserAccessCheckExpression<TaskUser>(x.User).Invoke(x)
                            && x.SomeBool == true));

More on LinqKit

答案 1 :(得分:0)

是的,所以,你不能这样做。 Expression<>Func<>之间存在差异。您正在尝试使用UserAccessCheckExpression作为功能。我不确定你要做什么,但你可以把它编译成一个函数,然后像你一样使用它:

var expr = UserAccessCheckExpression<TaskUser>(x.User);
var func = expr.Compile();
// Later use it like ...
var result = func();

但是我希望你在EF或Linq2Sql中使用它?在这种情况下,您需要重写表达式。它可以手工完成(不容易),或者更好,使用像PredicateBuilder这样的工具。