在C#中连接Lambda函数

时间:2009-01-29 14:25:19

标签: 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;
    }

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

编译器不喜欢'predicate = predicate + t =&gt; t.Response ....'或者。

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

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

6 个答案:

答案 0 :(得分:32)

“delegate + = method”是组播委托的操作符,用于将方法组合到委托中。 另一方面,“委托 - =方法”是从委托中删除方法的运算符。 它对Action很有用。

Action action = Method1;
action += Method2;
action += Method3;
action -= Method2;
action();

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

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

Func<int> func = () => 1;
func += () => 2;
func += () => 3;
int result = func();

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

在您的情况下,方法“t =&gt; t.Amount&lt; 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);
}

用法

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

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

答案 1 :(得分: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));
}

然后你会这样做:

Func<string, bool> predicate = And<string>(
    t => t.Length > 10,
    t => t.Length < 20);
编辑:这是一个更通用的解决方案,非常有趣,如果有点奇怪......

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

所以你可以然后实现And as:

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

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

答案 2 :(得分:13)

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

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

        bool b = predicate("12345");

这将返回TRUE,因为最后一个函数调用返回true(它小于20)。为了真正发挥作用,您需要致电:

predicate.GetInvocationList();

返回一个委托数组。然后,您需要确保它们全部返回true,以使最终结果为真。有意义吗?

答案 3 :(得分: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);
}

答案 4 :(得分:1)

如果你想组合谓词,试试这个;

public static Predicate<T> Combine<T>(params Predicate<T>[] predicates)
{
return t => predicates.All(pr => pr(t));
}

你这样称呼它;

Predicate<string> shortAndSweet = Combine<string>
(
    s => s.Length < 10,  // short,
    s => s == "sweet"    // and sweet
);

答案 5 :(得分:0)

+ =是专门用于支持向事件添加处理程序的语法糖。由于事件只是委托的一个特例,而Func也是委托,因此语法出现在这里工作。

但你确定它按预期工作吗?我的意思是,你期望进行AND或OR评估吗?如果你想要的话,你会如何实现相反的目标呢?你确定它不只是返回第一个结果吗?还是最后一次?