在 C# 中连接 Lambda 函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/491780/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 05:29:18  来源:igfitidea点击:

Concatenating Lambda Functions in C#

c#lambda

提问by John Oxley

Using C# 3.5 I wanted to build up a predicate to send to a where clause piece by piece. I have created a very simple Console Application to illustrate the solution that I arrived at. This works perfectly. Absolutely perfectly. But I have NO idea how or why.

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

When I say 'predicate +=', what does that mean? predicate -= appears to do nothing and ^=, &=, *=, /= aren't liked by the compiler.

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

The compiler doesn't like 'predicate = predicate + t => t.Response....' either.

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

What have I stumbled on? I know what it does, but how does it do it?

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

If anyone wants to go delve into more complicated lambda's, please do so.

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

采纳答案by Chaowlert Chaisrichalermpol

"delegate += method" is operator for multicast delegate to combine method to delegate. In the other hand "delegate -= method" is operator to remove method from delegate. It is useful for Action.

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

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

In this case, only Method1 and Method3 will run, Method2 will not run because you remove the method before invoke the delegate.

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

If you use multicast delegate with Func, the result will be last method.

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

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

In this case, the result will be 3, since method "() => 3" is the last method added to delegate. Anyway all method will be called.

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

In your case, method "t => t.Amount < 100" will be effective.

在您的情况下,方法“t => t.Amount < 100”将有效。

If you want to combine predicate, I suggest these extension methods.

如果要组合谓词,我建议使用这些扩展方法。

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

Usage

用法

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

EDIT: correct the name of extension methods as Keith suggest.

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

回答by Joel Coehoorn

The += is syntactic sugar specifically implemented to support adding handlers to events. Since events are just a special case of delegate, and Func is also a delegate, the syntax appearsto work here.

+= 是专门实现的语法糖,用于支持向事件添加处理程序。由于事件只是委托的一个特例,而 Func 也是委托,语法在这里似乎有效。

But are you sure it works as expected? By that I mean, do you expect an AND or OR evaluation? How would you implement the opposite if you wanted it? Are you sure it's not just returning the result of the first? Or the last?

但是你确定它按预期工作吗?我的意思是,您期望 AND 或 OR 评估吗?如果你想要它,你将如何实现相反的功能?你确定它不只是返回第一个的结果吗?还是最后一个?

回答by BFree

Actually, that doesn't work. Try to test it with a case where the first condition FAILS but the second one passes. You'll find that it'll return true. The reason is, because when dealing with multicast delegates that return values, only the last value is returned. For example:

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

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

        bool b = predicate("12345");

This will return TRUE because the last function call returns true (it's less than 20). In order to really make it work, you need to call:

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

predicate.GetInvocationList();

which returns an array of delegates. You then need to make sure they ALL return true, for the final result to be true. Make sense?

它返回一组委托。然后,您需要确保它们都返回 true,以便最终结果为 true。有道理?

回答by Jon Skeet

When you use += or -= when delegate types, that just gives a call to Delegate.Combineand Delegate.Remove.

当您在委托类型时使用 += 或 -= 时,只会调用Delegate.Combineand Delegate.Remove

The important thing about multicast delegates is that the return value of all but the last executed delegateis ignored. They all get executed (unless an exception is thrown), but only the last return value is used.

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

For predicates, you might want to do something like:

对于谓词,您可能想要执行以下操作:

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

You'd then do:

然后你会这样做:

Func<string, bool> predicate = And<string>(
    t => t.Length > 10,
    t => t.Length < 20);

EDIT: Here's a more general solution which is quite fun, if a bit bizarre...

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

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

So you couldthen implement And as:

因此,您可以将 And 实现为:

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

(I personally prefer this over using GetInvocationList(), because you end up with a predicate you can pass to other bits of LINQ etc.)

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

回答by JaredPar

Expanding on BFree's answer (+1'd it)

扩展 BFree 的答案(+1)

If you want to get the behavior you're looking for, you'll need to explicitly chain the predicates together. Here is an example

如果您想获得您正在寻找的行为,您需要显式地将谓词链接在一起。这是一个例子

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

回答by Steve Cooper

If you want to combine predicates, try this;

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

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

You call it like this;

你这样称呼它;

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