我可以像这样提取和重用整个表达式:
Expression<Func<User, int>> userExpression = x => x.Roles.Count()
但是有可能只提取一些x.Roles.Count()
部分,并在Expression<Func<User, T>>
我想要实现的是在不同选择中重用该部分,如:
users.Select(x => new AnotherClass { RoleCount = roleCountPartOfExpression})
和
users.Select(x => new OneMoreAnotherClass
{
AnotherProperty = roleCountPartOfExpression
});
那么在这种情况下{@ 1}}应该在LINQ to Entities中支持(因此创建一个方法,我将传递用户roleCountPartOfExpression
将无法工作)我也无法创建像return user.Roles.Count()
这样的选择的表达式,因为在这种情况下我需要创建Expression<Func<User, AnotherClass>>
,这将打破我的“可重用性”目标。
答案 0 :(得分:4)
如果您编译为Func<User, int>
,则可以在其他区域调用它:
Expression<Func<User, int>> userExpression = x => x.Roles.Count();
Func<User,int> userFunc = userExpression.Compile();
users.Select(x => new AnotherClass { RoleCount = userFunc(x) });
或者只是定义为Func
开头:
Func<User,int> userFunc = x => x.Roles.Count();
这是使用Linq-to-Objects还是别的?如果您需要将其保留为Expression
,因为Expression
会转换为其他内容(如SQL调用),您可以使用LinqKit的AsExpandable
,如下所示:
public static Expression<Func<User,int>> RoleCount()
{
return u => u.Roles.Count();
}
public static void DoStuff()
{
var roleCounter = RoleCount();
var query = users.AsExpandable()
.Select(u => roleCounter.Invoke(u));
}
答案 1 :(得分:1)
我们可以创建一个Combine
方法,它能够为一个对象选择一个选择器,然后另一个选择器也可以获取第一个选择器的输出以产生最终结果:
public static Expression<Func<TFirstParam, TResult>>
Combine<TFirstParam, TIntermediate, TResult>(
this Expression<Func<TFirstParam, TIntermediate>> first,
Expression<Func<TFirstParam, TIntermediate, TResult>> second)
{
var param = Expression.Parameter(typeof(TFirstParam), "param");
var newFirst = first.Body.Replace(first.Parameters[0], param);
var newSecond = second.Body.Replace(second.Parameters[0], param)
.Replace(second.Parameters[1], newFirst);
return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}
这使用以下帮助器方法将一个表达式的所有实例替换为另一个:
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
现在我们可以写:
Expression<Func<User, int>> userExpression = x => x.Roles.Count()
var query = users.Select(userExpression.Combine((x, count) =>
new OneMoreAnotherClass { AnotherProperty = count});
答案 2 :(得分:-1)
你可以用一个闭包来做到这一点:
User x = z; // assign local value
var countX = () => x.Roles.Count();
现在这将有效:
users.Select(x => new AnotherClass { RoleCount = countX() })