Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 组合两个Linq lambda表达式 表达式fn1=x=>x.PossibleSubPath.MyStringProperty; 表达式fn2=x=>x.Contains(“一些文字”);_C#_Linq_Expression - Fatal编程技术网

C# 组合两个Linq lambda表达式 表达式fn1=x=>x.PossibleSubPath.MyStringProperty; 表达式fn2=x=>x.Contains(“一些文字”);

C# 组合两个Linq lambda表达式 表达式fn1=x=>x.PossibleSubPath.MyStringProperty; 表达式fn2=x=>x.Contains(“一些文字”);,c#,linq,expression,C#,Linq,Expression,有没有办法创建一个新的lambda表达式,它基本上使用fn1的输出并将其用作fn2的输入 Expression<Func<MyObject, string>> fn1 = x => x.PossibleSubPath.MyStringProperty; Expression<Func<string, bool>> fn2 = x => x.Contains("some literal"); 表达式fnCombined=。。。 我知

有没有办法创建一个新的lambda表达式,它基本上使用fn1的输出并将其用作fn2的输入

Expression<Func<MyObject, string>> fn1 = x => x.PossibleSubPath.MyStringProperty;

Expression<Func<string, bool>> fn2 = x => x.Contains("some literal");
表达式fnCombined=。。。

我知道我可以立即创建函数,但问题是我正在编写一些通用代码,因此确实需要能够分别创建这两个函数,然后以Linq可以在我的数据库对象(实体框架)上使用它们的方式组合它们因此,从逻辑上讲,我们希望能够创建一个新的lambda,其中包含第一个函数的输入参数,以及一个使用该参数调用第一个函数的主体,然后将结果作为参数传递给第二个函数,然后返回该参数

我们可以使用
Expression
对象很容易地复制它:

Expression<Func<MyObject, bool>> fnCombined = ...
现在,我们可以编写适当的
组合
方法:

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);
    }
}
公共静态表达式组合(
这句话首先,,
表达(第二)
{
var param=表达式参数(typeof(T1),“param”);
var newFirst=new ReplaceVisitor(first.Parameters.first(),param)
.访问(第一个机构);
var newSecond=new ReplaceVisitor(second.Parameters.First(),newFirst)
.访问(第二机构);
返回表达式.Lambda(newSecond,param);
}
和一个简单的测试用例,来演示发生了什么:

public static Expression<Func<T1, T3>> Combine<T1, T2, T3>(
    this Expression<Func<T1, T2>> first,
    Expression<Func<T2, T3>> second)
{
    var param = Expression.Parameter(typeof(T1), "param");

    var newFirst = new ReplaceVisitor(first.Parameters.First(), param)
        .Visit(first.Body);
    var newSecond = new ReplaceVisitor(second.Parameters.First(), newFirst)
        .Visit(second.Body);

    return Expression.Lambda<Func<T1, T3>>(newSecond, param);
}
表达式fn1=x=>x.PossibleSubPath.MyStringProperty;
表达式fn2=x=>x.Contains(“一些文字”);
var组合=fn1.组合(fn2);
控制台写入线(复合);
将打印出:

param=>param.PossibleSubPath.MyStringProperty.Contains(“一些文字”)


这正是我们想要的;查询提供程序将知道如何解析类似的内容。

下面是一个显示表达式操作/组合的答案@谢谢你的链接;我在计算如何用另一个表达式替换一个表达式的所有实例时遇到了问题。如果
fn2
多次使用其参数,
fn1
将重复多次。希望这不是小事,或者由查询提供程序智能地处理,但这可能会导致大量工作被多次完成(类似于局部变量的事情应该可以工作,除非查询提供程序可能不支持)。@TimS。是的,我在回答中讨论了一下。老实说,我不认为这是一个主要问题,因为我希望DB端的查询优化器能够有效地处理此类情况。看起来OP正在研究的表达式类型也不会成为问题。很难说。正如您所提到的,局部变量几乎肯定无法正确解析。@Servy,您能否更新答案以反映,从第一个正文传递参数将不起作用,因为该参数是在单独表达式的范围内定义的,因此,当您组合表达式时,
x=>x.condition==true&&x.anotherCondition==false
第二个x与第一个x不同。(你也许可以更好地说出我想说的话)
public static Expression<Func<T1, T3>> Combine<T1, T2, T3>(
    this Expression<Func<T1, T2>> first,
    Expression<Func<T2, T3>> second)
{
    var param = Expression.Parameter(typeof(T1), "param");

    var newFirst = new ReplaceVisitor(first.Parameters.First(), param)
        .Visit(first.Body);
    var newSecond = new ReplaceVisitor(second.Parameters.First(), newFirst)
        .Visit(second.Body);

    return Expression.Lambda<Func<T1, T3>>(newSecond, param);
}
Expression<Func<MyObject, string>> fn1 = x => x.PossibleSubPath.MyStringProperty;
Expression<Func<string, bool>> fn2 = x => x.Contains("some literal");

var composite = fn1.Combine(fn2);

Console.WriteLine(composite);