在C#中连接Lambda函数

Joh*_*ley 27 c# lambda

使用C#3.5我想构建一个谓词,逐个发送到where子句.我创建了一个非常简单的控制台应用程序来说明我到达的解决方案.这非常有效.绝对完美.但我不知道如何或为什么.

    public static Func<Tran, bool> GetPredicate()
    {
        Func<Tran, bool> predicate = null;
        predicate += t => t.Response == "00";
        predicate += t => t.Amount < 100;
        return predicate;
    }
Run Code Online (Sandbox Code Playgroud)

当我说'谓词+ ='时,这是什么意思?谓词 - =似乎什么都不做,编译器不喜欢^ =,&=,*=,/ =.

编译器不喜欢'predicate = predicate + t => t.Response ....'.

我偶然发现了什么?我知道它的作用,但它是如何做到的?

如果有人想深入研究更复杂的lambda,请这样做.

Cha*_*pol 33

"delegate + = method"是多播委托的运算符,用于将方法组合到委托.另一方面,"委托 - =方法"是从委托中删除方法的运算符.它对Action非常有用.

Action action = Method1;
action += Method2;
action += Method3;
action -= Method2;
action();
Run Code Online (Sandbox Code Playgroud)

在这种情况下,只运行Method1和Method3,因为在调用委托之前删除了方法,所以不会运行Method2.

如果您使用带有Func的多播委托,则结果将是最后一个方法.

Func<int> func = () => 1;
func += () => 2;
func += () => 3;
int result = func();
Run Code Online (Sandbox Code Playgroud)

在这种情况下,结果将是3,因为方法"()=> 3"是添加到委托的最后一个方法.无论如何,所有方法都将被调用.

在您的情况下,方法"t => t.Amount <100"将是有效的.

如果你想组合谓词,我建议这些扩展方法.

public static Func<T, bool> AndAlso<T>(
    this Func<T, bool> predicate1, 
    Func<T, bool> predicate2) 
{
    return arg => predicate1(arg) && predicate2(arg);
}

public static Func<T, bool> OrElse<T>(
    this Func<T, bool> predicate1, 
    Func<T, bool> predicate2) 
{
    return arg => predicate1(arg) || predicate2(arg);
}
Run Code Online (Sandbox Code Playgroud)

用法

public static Func<Tran, bool> GetPredicate() {
    Func<Tran, bool> predicate = null;
    predicate = t => t.Response == "00";
    predicate = predicate.AndAlso(t => t.Amount < 100);
    return predicate;
}
Run Code Online (Sandbox Code Playgroud)

编辑:更正Keith建议的扩展方法的名称.


Jon*_*eet 20

当委托类型使用+ =或 - =时,只需调用Delegate.CombineDelegate.Remove.

关于多播委托的重要一点是忽略了除最后执行的委托之外所有委托的返回值.它们都被执行(除非抛出异常),但只使用了最后一个返回值.

对于谓词,您可能希望执行以下操作:

public static Func<T, bool> And<T>(params Func<T, bool>[] predicates)
{
    return t => predicates.All(predicate => predicate(t));
}

public static Func<T, bool> Or<T>(params Func<T, bool>[] predicates)
{
    return t => predicates.Any(predicate => predicate(t));
}
Run Code Online (Sandbox Code Playgroud)

然后你会这样做:

Func<string, bool> predicate = And<string>(
    t => t.Length > 10,
    t => t.Length < 20);
Run Code Online (Sandbox Code Playgroud)

编辑:这是一个更通用的解决方案,非常有趣,如果有点奇怪......

public static Func<TInput, TOuput> Combine<TInput, TOutput>
    (Func<TOutput, TOutput, TOutput> aggregator,
     params Func<TInput, TOuput>[] delegates) {

    // delegates[0] provides the initial value
    return t => delegates.Skip(1).Aggregate(delegates[0](t), aggregator);
}
Run Code Online (Sandbox Code Playgroud)

所以你可以实现And as:

public static Func<T, bool> And<T>(params Func<T, bool>[] predicates) {
    return Combine<T, bool>((x, y) => x && y, predicates);
}
Run Code Online (Sandbox Code Playgroud)

(我个人更喜欢使用它GetInvocationList(),因为你最终会得到一个谓词,你可以传递给其他LINQ等等)


BFr*_*ree 13

实际上,这不起作用.尝试用第一个条件FAILS但第二个条件通过的情况进行测试.你会发现它会回归真实.原因是,因为在处理返回值的多播委托时,只返回最后一个值.例如:

        Func<string, bool> predicate = null;
        predicate += t => t.Length > 10;
        predicate += t => t.Length < 20;

        bool b = predicate("12345");
Run Code Online (Sandbox Code Playgroud)

这将返回TRUE,因为最后一个函数调用返回true(它小于20).为了真正使它工作,你需要打电话:

predicate.GetInvocationList();
Run Code Online (Sandbox Code Playgroud)

它返回一个委托数组.然后,您需要确保它们全部返回true,以使最终结果为真.合理?


Jar*_*Par 6

扩展了BFree的答案(+ 1)

如果你想获得你正在寻找的行为,你需要明确地将谓词链接在一起.这是一个例子

public static Func<Tran, bool> GetPredicate()
{
    Func<Tran, bool> predicate1 = t => t.Response == "00";
    Func<Tran, bool> predicate2 = t => t.Amount < 100;
    return t => predicate1(t) && predicate2(t);
}
Run Code Online (Sandbox Code Playgroud)