【发布时间】:2012-11-22 12:50:44
【问题描述】:
使用来自各种 SO 帖子的信息,尤其是 blog(更正为使用 AndAlso 而不是 And)我已经设法将类似类型的 linq 表达式组合成一个谓词。但现在我想组合两个表达式,其中一个是另一个的输入。这是完全扩展的原始Expression;
private Expression<Func<T, bool>> ExpressionIsNamed(IEnumerable<EntityName> AccessorNames)
{
// works
Expression<Func<T, bool>> Texpr = x => x.Security.Readers.Any(n => AccessorNames.ToStringArray().Contains(n.Text));
return Texpr;
}
请注意,至关重要的是,我需要将这些作为 Expressions 进行管理,因为我的 DB 驱动程序需要遍历树并转换为本机调用,因此使用 Compile() 进行组合不是一个选项。
所以下面是我想与上面的Any() 调用结合的函数。最终输出的表达式必须是 Expression<Func<T, bool>> 类型,我需要将 x.Security.Readers 传递给这个类型。
public static Expression<Func<IEnumerable<EntityName>,bool>> AccessCheckExpression(IEnumerable<EntityName> AccessorNames)
{
return accessList => accessList.Any(n => AccessorNames.ToStringArray().Contains(n.Text));
}
我已经做到了这一点,但我正在努力研究如何从 accessCheck 换出 accessList => 并让它在单个表达式中使用 accessList。到目前为止,我有这个;
private Expression<Func<T, bool>> ExpressionIsNamed(IEnumerable<EntityName> AccessorNames)
{
Expression<Func<T, IEnumerable<EntityName>>> accessList = (T x) => x.Security.Readers;
Expression<Func<IEnumerable<EntityName>, bool>> accessCheck = SecurityDescriptor.AccessCheckExpression(AccessorNames);
// Combine?
Expression<Func<T, bool>> Texpr = ??? accessCheck + accessList ???
return Texpr;
}
[更新]
所以我还有一点;
class ParameterUpdateVisitor : System.Linq.Expressions.ExpressionVisitor
{
private ParameterExpression _oldParameter;
private ParameterExpression _newParameter;
public ParameterUpdateVisitor(ParameterExpression oldParameter, ParameterExpression newParameter)
{
_oldParameter = oldParameter;
_newParameter = newParameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (object.ReferenceEquals(node, _oldParameter))
return _newParameter;
return base.VisitParameter(node);
}
}
static Expression<Func<T, bool>> UpdateParameter<T>(
Expression<Func<T, IEnumerable<EntityName>>> expr,
ParameterExpression newParameter)
{
var visitor = new ParameterUpdateVisitor(expr.Parameters[0], newParameter);
var body = visitor.Visit(expr.Body);
return Expression.Lambda<Func<T, bool>>(body, newParameter);
}
然后我可以编译;
UpdateParameter(accessList, accessCheck.Parameters[0]);
感谢所有Invoke() 的建议,但我的猜测是,当他们使用 MongoDB 驱动程序时,它不会喜欢InvocationExpression。但是,Invoke 和我上面的代码现在都以完全相同的方式失败。即;
System.ArgumentException: Expression of type
'System.Func`2[MyLib.Project,System.Collections.Generic.IEnumerable`1[MyLib.EntityName]]'
cannot be used for parameter of type
'System.Collections.Generic.IEnumerable`1[MyLib.EntityName]'
因此,隐式参数 x.Security.Readers 似乎与普通的旧 IEnumerable<EntityName> 类型不同
【问题讨论】:
-
你错过了
ExpressionIsNamed定义中的类型参数。 -
@HamletHakobyan:不一定。它们的泛型参数可以在包含此私有方法的类上定义。
-
@DanielHilgarth 好的。谢谢!