利用来自不同 Stack Overflow 帖子和尤其是这篇博客(已更正为使用 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;
}
请注意,关键是我需要将这些内容管理为表达式,因为我的DB驱动程序需要遍历树并转换为本机调用,因此使用Compile()进行组合不是一个选项。
因此,以下是我想要与上面的
Any()
调用组合的函数。最终输出的Expression需要是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
的定义中,您错过了类型参数。 - Hamlet Hakobyan