gpt4 book ai didi

c# - 组合两个 Linq 表达式

转载 作者:太空狗 更新时间:2023-10-29 23:16:22 24 4
gpt4 key购买 nike

使用来自各种 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;
}

请注意,至关重要的是,我需要将它们作为表达式 进行管理,因为我的数据库驱动程序需要遍历树并转换为 native 调用,因此使用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));
}

我已经做到这一点了,但我正在努力弄清楚如何换出 accessList =>来自 accessCheck并让它使用 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>

最佳答案

VisitorExpression 是您的 friend 。这是合并类似内容的简化但完整的示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

class Source {
public List<Value> Values {get;set;}
}
class Value {
public int FinalValue {get;set;}
}
static class Program {
static void Main() {
Expression<Func<Source, IEnumerable<Value>>> f1 =
source => source.Values;
Expression<Func<IEnumerable<Value>, bool>> f2 =
vals => vals.Any(v => v.FinalValue == 3);

// change the p0 from f2 => f1
var body = SwapVisitor.Swap(f2.Body, f2.Parameters[0], f1.Body);
var lambda = Expression.Lambda<Func<Source, bool>>(body,f1.Parameters);
// which is:
// source => source.Values.Any(v => (v.FinalValue == 3))
}

}
class SwapVisitor : ExpressionVisitor {
private readonly Expression from, to;
private SwapVisitor(Expression from, Expression to) {
this.from = from;
this.to = to;
}
public static Expression Swap(Expression body,
Expression from, Expression to)
{
return new SwapVisitor(from, to).Visit(body);
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}

编辑:在您的情况下,这将是:

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);


var body = SwapVisitor.Swap(accessCheck.Body,
accessCheck.Parameters[0], accessList.Body);
return Expression.Lambda<Func<T, bool>>(body, accessList.Parameters);
}

关于c# - 组合两个 Linq 表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13513134/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com